JVM和GC学习总结

JVM部分

线程共享的区域:方法区、堆区
线程独享:虚拟机栈、本地方法栈、程序计数器

1、虚拟机栈:

跟线程共存亡,每个线程在创建时都会去创建一个虚拟机栈,
里面是一个一个的栈帧,每个栈帧都对应着一个方法,方法的执行的返回就伴随着入栈和出栈
线程私有,
保存方法的局部变量、部分结果,并参与方法的调用和返回
jvm允许根据需要动态调整栈的大小,
超过固定栈大小则会抛出StackOverflowError栈溢出的异常。
在无法获取更多内存来扩展栈时、或者在创建线程时没有足够空间来创建对应的虚拟机栈,则会抛出OutOfMemoryError异常
栈能够快速有效的分配内存,访问速度仅次于程序计数器
可以使用-Xss选项来设置线程的最大栈空间,栈的大小直接决定了函数调用的最大可达深度。

2、本地方法栈

线程私有,
用来给本地方法调用提供的内存空间,这里的方法并不是由java代码编写的,是利用native定义的方法来进行调用的其他语言(c、c++)编写的。

3、程序计数器:

线程私有。
java代码需要被编译器编译为字节码文件(也就是JVM指令),字节码并不能直接被机器所执行,解释器会将字节码转化为机器码,然后交给cpu来执行,
,程序计数器就是用来存储下一条将要被执行的指令的地址,
它是jvm中唯一一个不会出现内存溢出的区
占用内存很小,也是jvm中运行最快的区
程序的流程控制、循环、跳转、异常处理、线程恢复都需要依赖程序计数器进行

4、堆区:

堆区是JVM最大的一块内存区域,也是GC主要管理的区域,在JVM启动时被创建,所有线程共享堆区,
jvm规范中:”几乎“所有的实例对象和数组都应当在堆区,还有一部分会在栈中保存
jdk1.87之前堆区分为新生代、老年代、永久代
jdk1.8之后堆区分为新生代、老年代、元空间
新生代中包含:伊甸园(Eden)、幸存者0区Survivor0,幸存者1区Survivor1
伊甸园(Eden):幸存0区:幸存1区=8:1:1(在新生区中三个区域的比例)	
新生代:老年代=1:2(新生代和老年代在堆中的占比)
几乎所有的java对象都是在Eden中被创建的
绝大部分的java对象销毁都是在新生代进行了

5、方法区

线程共享区域,
在jvm启动时被创建,
用来存储已经被加载的类型信息、常量、静态变量即时编译器编译后的代码缓存
和堆区一样在内存中可以是不连续的区域
方法区的大小决定了系统可以加载多少类,
系统的类加载过多、大量生成反射类,加载大量jar包,都会引发java.lang.outOfMemoryError的异常
jvm关闭后就会释放这一部分的内存

GC部分

GC回收没有存活的对象,判断对象是否存活的方法有两种:

1、引用计数:每个对象新增一个引用时,计数加1,释放一个引用时引用减1,无法解决对象相互引用问题
2、可达分析:GC Roots 作为所有对象的根对象,当从GC Roots到某个对象之间不存在任何的引用链连接时,说明该对象不可达

可以作为GC回收的对象:

1、虚拟机栈中引用的对象
2、方法区中类静态属性引用的对象
3、方法区中常量引用的对象
4、本地方法栈中 JNI(Native 方法)引用的对象
5、Java 虚拟机中内部的引用
6、synchronized 持有的对象
7、JMXBean、JVMTI 中注册的回调、本地代码缓存

GC分为Minor GC和Full GC,

Minor GC的时候要远小于Full GC,
Minor GC都是在新生代区域进行的,新生代区域太大会导致老年代空间的缩小,从而会引发频繁的调用Full GC,清理新生代所花费的时间也更长
Full GC是发生在老年代
GC在执行时候java所有的线程都将暂停,至于native代码可以执行,但是不能和jvm交互,这种全局暂停被称为STW(stop the world)

GC流程:

1、新的对象优先在Eden区域被创建,如果对象大小大于Eden区域一半的大小,会直接进入老年代
2、如果Eden中的对象满了的话,会进行一次minor gc,存活的对象将会复制到Survivor0区(幸存区),
3、下一次Minor GC时会将Eden和幸存者0区的对象复制到Survivor1区,(这时Survivor0区已经被清空)
4、在下一次Minor GC的时候,会将Eden和Survivor1区的对象复制到Survivor0区(此时Survivor1区被清空)
一直往复循环3、4,Survivor的两个区中总有一个为空的
在新生代中所有的对象存活周期都很短,并且对象的大小都不大,采用的这种清理的方法成为,stop-copy(停止-复制)法
5、在一次Minor GC后存活下来的对象的年龄就会+1,当对象年龄达到15(可使用参数调整这个大小)时,该对象就会被复制到老年代。
6、进行Full GC的情况:
	1、当老年代的空间不足、
	2、方法去空间不足、
	3、在对象年龄达到15岁往老年代复制的时候老年代剩余空间不足时、
	4、调用System.gc的时候
在新生代设置两个Survivor区的意义:
	如果只有一个Survivor区的话,
		如果使用采用”停止-复制“算法Survivor很容易占满,会很频繁的进行Minor GC,
		如果采用”标记-清除“的算法,内存的碎片化就会很严重
	设置两个Survivor区并且采用”停止-复制“的算法时,能保证Survivor0或者Survivor1中保存的对象在内存中是一片连续的内存,避免的内存碎片化的产生。
	
	Survivor区新生代和老年代之间的缓冲区,避免老年代很快被填满,减少Full GC发生的次数,

标记-清除算法:

该算法分为两个阶段,第一个阶段将存活的对象打上标记,第二阶段对没有标记的对象进行清理
缺点:1、标记和清除的算法效率都不高
	2、容易产生很多内存的碎片,导致大对象无法成功分配到联系的内存,从而过早的引发GC
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个小白QAQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值