jvm_垃圾收集算法讲解(二)

使用PretenureSizeThreshold可以进入指定进入老年代的对象大小,-XX:MaxTenuringThreshold这个对象

经历多少次GC不被释放才会进入到老年代,PretenuredSizeThreshold多大的对象是直接进入老年代,比如我设置

1M,如果你超过1M的大小,那我直接给他放在老年代,是可以这么去做的,但是要注意TLAB是有限分配空间,这个参数

虽然可以指定这个对象多大才可以直接进入老年代

首先我们看一下刚才配置的参数是什么意思,我的上限是1K,如果是大于1K就直接给你扔到老年代了,就不在新生代

玩了,然后最大初始化都是30M,用串行垃圾收集器,打印GC的详细信息,然后你的对象大于1K,就直接扔到老年代,

new一个map,然后for循环多少次,我要for循环,循环了5*1024次,然后每次去申请1M的内存,1K肯定是大于1000的

也就是我这么多次循环,按理来说,这么大的数据应该直接分配到老年代,老年代used了0%,基本都分配在新生代里

了,这一块有一个概念,其实我们现在开启了一个线程,就是咱们的main线程,TLAB区会优先分配内存


TLAB区域全称叫做Thread Local Allocation Buffer,是本地分配的缓存,主线程本地分配缓存的东西,从名字

上来看,是一个线程专用的内存分配区域,每个内存都有TLAB区,JAVA的JDK会有一个优化的动作,会在线程启动

的时候先配一块独立的内存空间,这个空间当时没有明确的去说,我说了你也不知道是干啥的,先让你们有一个概念

就完事了,现在我跟你们说,这个空间就是TLAB,线程启动了就会有这么一个空间,来帮你做一系列的事情,帮你做

优化,这个就是Thread Local Allocation Buffer,它是为了加速对象分配而产生的,或者说提高线程的性能,

每个线程都会产生TLABE区,然后该线程独享的工作区域,JAVA虚拟机使用这个中TLAB区来避免多线程冲突问题,

提高了对象分配的效率,也提高了线程的性能,不要每次去取数据都去主内存去加载,直接在我的内存中间做就可以

TLAB区一般不会特别大,当大对象无法在TLAB区的时候,才会去分配到堆上.

这是JAVA的堆heap,当线程启动的时候会有一个TLAB区,一般杀鸡不用宰牛刀,小对象我直接扔到TLAB玩就是了,

太大了分配不了了我就直接放在堆中,放在Eden区,放在s0和s1区,放在老年代,默认JDK是使用TLAB区的
-XX:+UseTLAB 使用TLAB

-XX:+TLABSize 设置TLAB的大小

线程启动的时候我们给TLAB分配10M,这块还有一个特性,一般TLAB区是不需要你做任何事的,这个参数默认是有的,

设置维护进入TLAB空间的单个对象的大小,我们有一个对象到底是进入JAVA堆这里,还是进入线程TLAB区中,

它这个参数维护的,它是一个比值,默认是存在的,也就是整个对象如果大于1/64的话,比如我给你分配64M,整个的

大小是64M,然后我的这个数据是1.1M,那这个数据就不会分配到TLAB中,而是直接放在heapJAVA堆中,新生代的

Eden区,这个比值是可以设置的,-XX:+PrintTLAB查看TLAB详细信息,-XX:ResizeLAB 自动去调整

TLABRefillWasterFraction的阀值,其实这些东西都是JVM提供的,不需要做任何操作,其实就是你写代码的时候

你什么都不用干,不管这件事,但是如果有实际上的工作,如果有需求的话,如果你做一个比较核心的业务模块,

如果你做涉及到转账的业务,这些东西你就不得不用一下,能提高一些性能,自动调节阀值,刚才的原因无非是因为

不到1K的东西太小了,它会在我线程直接启动的时候,直接进入到TLAB中了,所以我们看到老年代的参数,怎么去

起到作用呢,我们加上最后1行话

-XX:-UseTLAB,注意这里前面是减号,前面已经说了加号表示启用,减号表示禁用,禁用TLAB区,强制把数据都分配

到老年代,那这回我们看到了

当然这不是绝对的,大部分的数据确实都进入到了老年代了,只有非常非常细微不到1M的数据不是绝对的


对象创建的流程图

非常细粒度的流程图,用new关键字去实例化的时候,首先在栈上分配,是一个比TLAB区更提前的一个概念,这个就是

保存在JAVA的Stack上了,这个使用temp变量可能会放在栈上分配,如果满足我就放在栈上,如果失败我就尝试放在

TLAB区,满足就放在TLAB区,如果还是不满足,判断对象是否能进入老年代,因为这边是把TLAB区禁用了之后,它往

右边走,去判断-XX:PretenuredSizeThreshold=1000这个值看有没有超过1000,超过1000就直接进入老年代,

就不往新生代放了,最后整个都失败,才放入到eden区,它是一个很细粒度的流程

没有禁用TLAB,他就就放在新生代里了,因为TLAB也是基于内存的,你得通过-XX:PrintTLAB去打印才能看的出来

使用TLAB区,加速我的方法的调用,然后这里面有PrintTLAB,然后加上PrintGC,然后给TLAB声明一个大小,

差不多100K,这个参数是自动调整大小,-XX:DoEscapeAnalysis 这是一个系统级的逃逸分析参数,你只有把它

禁用了之后它才能打印出来,TLAB这个东西是线程独有的,通过普通的JVM是看不出来效果的,因为JVM设计到很多

的东西,它都是默认开启了,有些东西你是需要禁用的,TLAB默认是启动的,逃逸分析参数是别把内核的东西给屏蔽

掉了,它这个词本身就是禁用,然后设置减号就是关闭逃逸信息

现在是把逃逸信息给加上了

这个时候你就可以看到TLAB信息的打印了,其实这里面的参数可读性是挺复杂的,你可以找找资料,总之最后我们

把逃逸信息给禁用之后,就能看到这个结果了,如果你把这个去掉了,就看不到了TLAB的详细信息了,它可能更快了,

因为你开启了优化可能就更快了,但是你看不到TLAB分配空间的信息,因为他是系统内核级的,他是线程内核级的,

所以说你要看到的话,正常工作的话你都不要看到这些参数,配置这些参数反而性能降下去了,但是你要是看到详细

信息你就可以把它加上,这过程就可以看到打印的耗时

如果你把TLAB区禁用的话,就是设置减,线程会向主内存去加载一些数据,相对来说就比较耗时

这块就是独立的线程内存空间,是对我们线程优化是很好的,其实本质也是属于堆一块的,其实这里是一个,逻辑的

概念,并不是一个物理的概念,为什么分配到Eden区里了,它是一个逻辑的概念,并不是一个屋里的概念,物理的概念

就是堆,无论是新生代还是老年代,反正都是堆空间,计算你开启一个线程,你去运行,那也是用到了JAVA里的堆了,

TLAB只是一个逻辑的概念,并不是说我这里有一个TLAB区,它是当线程启动的时候,JVM才会给他一块区域,这块区域

叫TLAB,这个是一个逻辑的概念

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值