如何减少full gc的数量
可以采用以下措施来减少Full GC的次数:
- 增加方法区的空间;
- 增加老年代的空间;
- 减少新生代的空间;
- 禁止使用System.gc()方法;
- 使用标记-整理算法,尽量保持较大的连续内存空间;
- 排查代码中无用的大对象。
对象如何晋升到老年代?
虚拟机给每个对象定义了一个对象年龄(Age)计数器,存储在对象头中。对象通常在Eden区里诞生,如果经过第一次MinorGC后仍然存活,并且能被Survivor容纳的话,该对象会被移动到Survivor空间中,并且将其对象年龄设为1岁。对象在Survivor区中每熬过一次MinorGC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15),就会被晋升到老年代中。对象晋升老年代的年龄阈值,可以通过参数-XX:MaxTenuringThreshold设置。
为什么要设置两个Survivor区域?
设置两个 Survivor 区最大的好处就是解决内存碎片化
因为 Survivor 有 2 个区域,所以每次 Minor GC,会将之前 Eden 区和 From 区中的存活对象复制到 To 区域。第二次 Minor GC 时,From 与 To 职责兑换,这时候会将 Eden 区和 To 区中的存活对象再复制到 From 区域,以此反复。
这种机制最大的好处就是,整个过程中,永远有一个 Survivor space 是空的,另一个非空的 Survivor space 是无碎片的
内存泄漏和内存溢出有什么区别?
内存泄漏(memory leak):内存泄漏指程序运行过程中分配内存给临时变量,用完之后却没有被GC回收,始终占用着内存,既不能被使用也不能分配给其他程序,于是就发生了内存泄漏。
内存溢出(out of memory):简单地说内存溢出就是指程序运行过程中申请的内存大于系统能够提供的内存,导致无法申请到足够的内存,于是就发生了内存溢出。
内存泄漏和内存溢出的解决方案
- 内存泄漏的解决方案:
- 手动释放内存资源:确保程序中所有动态分配的内存都被正确释放。当内存不再需要时,可以通过手动释放内存资源来避免内存泄漏问题。
- 垃圾回收:采用自动内存管理机制,如垃圾回收器来回收不再使用的内存资源。
- 使用内存分析工具:使用内存分析工具来识别内存泄漏的根本原因。内存分析工具可以帮助开发者找到内存泄漏的位置并解决问题。
避免内存泄漏的几点建议:
- 尽早释放无用对象的引用。
- 避免在循环中创建对象。
- 使用字符串处理时避免使用String,应使用StringBuffer。
- 尽量少使用静态变量,因为静态变量存放在永久代,基本不参与垃圾回收。
2.内存溢出的解决方案:
- 调整 JVM 参数:通过调整 JVM 参数来增加系统内存容量。例如,通过设置-Xmx参数来增加Java虚拟机可用内存的上限。
- 优化代码:编写高效的代码,避免在程序运行时占用大量内存资源。
- 增加系统内存:增加系统内存容量,以便程序可以申请更多的内存资源。
- 使用内存分析工具来分析应用程序的内存使用情况,找到程序中存在的内存泄漏和内存浪费问题。
- 查看错误日志,看有没有“OutOfMemory”错误
哪些区域会OOM,怎么触发OOM
- 堆(Heap):堆是Java虚拟机管理的主要内存区域,用于存储所有的对象实例和数组。如果程序申请的堆内存超出了JVM可用的堆内存大小,就会导致OOM错误。
- 虚拟机栈(Stack):栈用于存储线程执行时的方法调用和局部变量等信息,栈的大小通常是固定的。如果栈空间被占满,就会导致栈溢出错误。
- 方法区(Method Area):方法区用于存储类的元数据信息、静态变量和常量池等数据。如果方法区空间被占满,就会导致OOM错误。
- 本地方法栈(Native Stack):本地方法栈用于存储本地方法的信息,与Java虚拟机实现相关。如果本地方法栈空间被占满,就会导致栈溢出错误
- 本地直接内存溢出:直接内存(Direct Memory)的容量大小可通过-XX:MaxDirectMemorySize参数来指定,如果不去指定,则默认与Java堆最大值(由-Xmx指定)一致。如果直接通过反射获取Unsafe实例进行内存分配,并超出了上述的限制时,将会引发OOM异常