有这篇文章就够了——JVM TLAB 分析(三)

开课吧开课吧锤锤2021-04-21 09:39

点赞
有用
分享分享

    Java编程语言是一种简单、面向对象、分布式、解释型、健壮安全、与系统无关、可移植、高性能、多线程和动态的语言。如今Java已经广泛应用于各个领域的编程开发。

Java

    5.TLAB要解决的问题以及带来的问题与解决方案的思考

    TLAB要解决的问题很明显,尽量避免从堆上直接分配内存从而避免频繁的锁争用。

    引入TLAB之后,TLAB的设计上,也有很多值得考虑的问题。

    5.1.引入TLAB后,会有内存孔隙问题,还可能影响GC扫描性能

    出现孔隙的情况:

    当前TLAB不够分配时,如果剩余空间小于最大浪费空间限制,那么这个TLAB会被退回Eden,重新申请一个新的。这个剩余空间就会成为孔隙。

    当发生GC的时候,TLAB没有用完,没有分配的内存也会成为孔隙。

Java

    如果不管这些孔隙,由于TLAB仅线程内知道哪些被分配了,在GC扫描发生时返回Eden区,如果不填充的话,外部并不知道哪一部分被使用哪一部分没有,需要做额外的检查,那么会影响GC扫描效率。所以TLAB回归Eden的时候,会将剩余可用的空间用一个dummyobject填充满。如果填充已经确认会被回收的对象,也就是dummyobject,GC会直接标记之后跳过这块内存,增加扫描效率。但是同时,由于需要填充这个dummyobject,所以需要预留出这个对象的对象头的空间。

    5.2.某个线程在一轮GC内分配的内存并不稳定

    如果我们能提前知道在这一轮内每个线程会分配多少内存,那么我们可以直接提前分配好。但是,这简直是痴人说梦。每个线程在每一轮GC的分配情况可能都是不一样的:

    不同的线程业务场景不同导致分配对象大小不同。我们一般会按照业务区分不同的线程池,做好线程池隔离。对于用户请求,每次分配的对象可能比较小。对于后台分析请求,每次分配的对象相对大一些。

    不同时间段内线程压力并不均匀。业务是有高峰有低谷的,高峰时间段内肯定分配对象更多。

    同一时间段同一线程池内的线程的业务压力也不一定不能做到很均匀。很可能只有几个线程很忙,其他线程很闲。

    所以,综合考虑以上情况,我们应该这么实现TLAB:

    不能一下子就给一个线程申请一个比较大的TLAB,而是考虑这个线程TLAB分配满之后再申请新的,这样更加灵活。

    每次申请TLAB的大小是变化的,并不是固定的。

    每次申请TLAB的大小需要考虑当前GC轮次内会分配对象的线程的个数期望

    每次申请TLAB的大小需要考虑所有线程期望TLAB分配满重新申请新的TLAB次数

    以上内容由开课吧老师干货满满张哈希提供,更多Java教程尽在开课吧广场Java教程频道。

有用
分享