说说JVM对象创建与内存分配的流程
首先经过类加载检查,将需要的类加载到jvm内存中,即经过加载、验证、准备、解析、初始化
其次分配内存(指针碰撞/空闲列表)
再初始化(给成员变量赋初始值null/0)
之后设置对象头
最后执行init()方法
内存分配采用的方法
指针碰撞
内存空间分配规则时,有一个已使用和未使用的临界指针,分配内存时只需要往后空出几个空间。这就是指针碰撞
空闲列表
内存分配不规则时,已被使用的内存和空闲的内存交错在一起,虚拟机就会维护一个列表,记录可用的内存空间。当对象创建时,就可以找到空闲的内存进行分配
在并发对象创建时的处理流程
CAS乐观锁+失败重试
多个线程一起抢内存空间,只能有一个线程抢到,其他线程再去抢其他的内存空间
本地线程分配缓冲
每个线程都在堆中事先规划一块独立的线程专属空间,线程在new对象时,只向自己的内存空间存放,也就是jvm需要开启TLAB
对象内存分配流程
线程new对象时,会先进行对象逃逸分析,非对象逃逸的话优先存放去栈上,如果栈上分配不下的话,还是会在堆上分配
在堆上分配优先存放Eden区(TLAB本地线程缓冲),但如果对象太大会分配到老年代
长期存活的对象直接进入老年代(默认经过15次FullGC)。
ThreadLocal为什么会导致内存泄漏?如何解决的?
ThreadLocal的作用,可以在这个线程中被线程的方法调用,类似缓存。每个线程中都有一个ThreadLocalMap属性,key值为ThreadLocal,value为缓存值。key值是弱引用,value值是强引用,GC时会清除弱引用,但是强引用value不会被清除。
在线程池中,一旦给ThreadLocalMap赋值了,没有手动remove(),那么就会造成内存泄漏的问题。
解决方法:
手动执行remove()方法。
避免线程池中使用ThreadLocalMap。
平时要做好监控和预防。
什么是三色标记?
是CMS的底层算法逻辑。
分为黑色、灰色、白色
黑色:表示对象和它引用的对象都已被检查且都是可达的
灰色:表示对象已被检查是可达的,但是它引用的对象未被检查
白色:表示对象和它引用的对象都未被检查。白色对象可能是垃圾,直到它被证明为可达的
说说你们生产环境遇到的哪些JVM内存问题?是怎么解决的?
内存泄漏,线程池中使用了ThreadLocalMap,未手动remove()
频繁fullGC问题,一个高并发的系统,由于老年代内存不足,导致频繁Full GC,解决方法:
1、调整堆内存配置,增加老年代内存空间
2、优化对象的生命周期,减少不必要的对象创建
内存碎片的问题:批处理调度,频繁创建和释放大对象,导致内存碎片化
解决方法:
1、调整内存配置,增加连续内存块的大小
2、减少大对象的频繁分配和释放
3、使用G1垃圾回收器(底层采用复制算法)
4、CMS垃圾回收器(底层采用标记清除算法),可修改参数更改为标记整理算法,减少内存碎片的产生