JVM内存模型
简图
程序计数器:jvm中的PC寄存器是对物理PC寄存器的一种抽象模拟。用来存储指向下一条指令的地址,由执行引擎读取下一条指令。不存在内存溢出
本地方法栈:支持对本地方法的调用
虚拟机栈:早期也叫java栈。内部保存栈帧,一个栈帧对应一个java方法。栈解决程序运行问题,即程序如何执行,如何处理数据。只有进栈出栈,不需要垃圾回收,溢出就挂了,发生OOM。遵循先进后出。栈帧中存储这局部变量表。。。
堆:用来存放java对象实例。一个jvm实例只存在一个堆内存。所有java线程共享java堆
方法区:所有线程共享,存储元数据,例如类结构信息、以及对应的运行时常量池、字段、方法代码等jdk7叫永久代,jdk8叫元空间,元空间与永久代最大的区别在于:元空间不在虚拟机设置的内存中,而是使用本地内存。
堆内存细分
逻辑上的
类加载过程
jvm跨平台
不要求源程序必须用java来写,只要提供遵循jvm规范的字节码文件即可
垃圾回收机制
什么是垃圾
垃圾值得是在运行程序中没有任何指针指向的对象,这个对象就是需要被垃圾回收
为什么需要GC
不进行垃圾回收,内存迟早被消耗完
可以清理内存碎片,以便jvm将整理出来的内存分配给新的对象
没有GC不能保证程序的正常运行
好处:
降低内存泄露和内存溢出的风险
自动内存管理机制,让程序员可以更专注于业务
GC的作用区域
GC的作用区域是方法区和堆
三种GC
jvm在进行GC时,并非每次都对上面三个内存(新生代、老年代、方法区)区域一起回收,大部分时候回收的都是新生代。
针对hotSpot vm的实现,它里面的GC按照回收区域分为两大类型:一种是部分回收(partial GC),一种是整堆回收(Full GC)
部分回收(partial GC):不是完整收集整个java堆的垃圾。其中又分为
新生代收集(Minor GC/Young GC):只是新生代(Eden/s0/s1)的垃圾收集
老年代收集(Major GC/Old GC):只是老年代的垃圾收集
整堆收集(Full GC):收集整个java堆和方法区
年轻代Minor GC触发机制:
- 当年轻代空间不足时,触发Minor GC,之力指的是Eden区满了,Survivor区满不会引发GC。
- 因为java对象大多具备朝生夕死的特性,所以Minor GC非常频繁,一般回收速度也比较快
- Minor GC会引发STW,暂停其他用户的线程,等待垃圾回收结束,用户线程才恢复运行
老年代Major gc触发机制:
- 老年代空间不足,会尝试触发Minor GC,如果之后空间还是不足,会触发Major GC
- 如果Major GC后,内存还不足,就报OOM了
Full GC触发机制:
- 调用system.gc()时,系统建议执行Full GC ,但是不是必然执行
- 老年代空间不足
- 方法区空间不足
- 通过Minor GC 后进入老年的的平均大小大于老年代的可用内存
- 由Eden区,from区向to区复制时,对象大小大于to区可用内存,则把该对象转到老年代,且老年代的可用内存小于该对象大小
垃圾回收相关的算法
标记阶段:
引用计数算法
可达性分析算法
清除阶段:
标记-清除算法
finalization机制
java提供对象终止机制,允许开发人员提供对象被销毁之前的自定义处理逻辑
finalize()方法允许在子类中被重写,用于在对象被回收时进行资源释放
不要主动调用某个对象的finalize()方法,应该交给垃圾回收机制调用
在finalize()时可能导致对象复活
finalize()方法的执行时间是没有保障的,完全由GC线程决定,极端情况下,若不发生GC,则finalize()将没有执行机会
优先级低的线程主动调用finalize()也不一定马上执行
相关概念
System.gc()
仅仅是提醒进行垃圾回收,不确定是否马上执行gc
内存溢出与内存泄露
内存溢出:
程序占用的内存增长速度非常快,造成垃圾回收已经跟不上内存消耗 OOM
OOM:没有空闲内存,并且垃圾收集器也无法提供更多内存
java虚拟机堆内存设置不够 可以通过-Xms、-Xmx来调整
代码中创建了大量大对象,并且长时间不能被垃圾收集器收集(存在引用)
内存泄露:
严格来说,只有对象不会再被程序用到了,但是GC又不能回收他们的情况,才叫内存泄露
但是一些不太好的实践,导致对象的声明周期变得很长甚至导致OOM,也可以叫做宽泛意义上的“内存泄露”。
一旦内存泄漏,程序中的可用内存会被逐步蚕食,知道耗尽所有内存,最终出现OOM
常用命令
-Xms:初始堆大小,默认为物理内存的1/64(<1GB);空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制
-Xmx:最大堆大小,默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制
-Xmn:新生代的内存空间大小
-XX:SurvivorRatio:默认值8, eden:from:to = 8:1:1
-Xss:每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。应根据应用的线程所需内存大小进行适当调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。一般小的应用, 如果栈不是很深, 应该是128k够用的,大的应用建议使用256k。
-XX:PermSize:设置永久代(perm gen)初始值。默认值为物理内存的1/64。
-XX:MaxPermSize:设置持久代最大值。物理内存的1/4。
标签:java,回收,线程,内存,JVM,GC,垃圾 From: https://www.cnblogs.com/deity-night/p/17197983.html