JVM

jvm内存为什么要分新生代与老年代

https://blog.csdn.net/weixin_34347651/article/details/92907820
http://haodro.com/post/1413.html

怎么排查堆内存溢出

https://blog.csdn.net/minkeyto/article/details/105431553

CMS并发清理的过程中突然来了很多对象导致内存放不下会发生什么

会触发full gc。

解决对象的跨代引用

所有涉及部分区域收集的垃圾收集器如G1,CMS都会面临跨代引用的问题。

垃圾收集器在新生代中建立了名为记忆集的数据结构用以避免把整个老年代加进GC ROOTS的扫描范围。
记忆集是一种抽象的数据结构,用于记录从非收集区域指向收集区域的指针集合。卡表是记忆集的一种实现形式,因为它的记录精度是卡精度,即每个记录精确到一块内存区域。
卡表可以理解为map,它记录的是卡表项到具体内存区域(卡页)的映射。一个卡页通常包含不止一个对象,只要这个卡页中有一个对象的字段存在着跨代指针,那就将对应卡表数组的元素值标识为1,称为这个元素变脏。
在垃圾收集时,只要筛选出卡表中变脏的元素,就能得出哪些卡页中含跨代指针,把它们加入GC ROOTS的扫描范围。

我们已经解决了如何使用记忆集来缩减扫描范围,但是还没有解决卡表元素如何维护的问题,例如它们何时变脏、谁把它们变脏。
hotspot是通过写屏障来维护卡表的:在引用对象赋值语句后面添加一条JVM指令。
应用写屏障后,虚拟机就会为所有赋值操作生成相应的指令,一旦收集器在写屏障中增加了更新卡表操作,每次引用对象更新,就会产生开销,不过这个开销与minor gc扫描整个老年代的代价相比还是小得多的。
除了开销外,卡表在高并发下还面临着伪共享的问题(一个卡表元素占一个字节)。一种简单的解决方案是不采用无条件的写屏障,而是当卡表元素未被标记过时才将其变脏,已变脏就不再理会。

在JVM的新生代内存中,为什么除了Eden区,还要设置两个Survivor区?

https://blog.csdn.net/bishe_teacher/article/details/107007445

CMS为什么采用“标记-清除”算法

https://blog.csdn.net/weixin_30480075/article/details/95598789

JVM的分代年龄为什么是15

https://blog.csdn.net/OrangeRawNorthland/article/details/82822258

什么时候进入老年代?

https://blog.csdn.net/dl674756321/article/details/102871999

各回收算法优缺点

引用计数法、标记清除法、标记压缩法、复制算法、分代算法等。

引用计数器法:假设有一个对象A,任何一个对象对A的引用,那么对象A的引用计数器+1,当引用失败时,对象A的引用计数器就-1,如果对象A的引用计数器的值为0,就说明对象A没有引用了,可以被回收。
优点:
1.实时性较高,无需等到内存不够的时候,才开始回收,运行时根据对象的计数器是否为0,来进行回收。
2.在垃圾回收过程中,应用无需挂起,如果申请内存时,内存不足,则立刻报outofmember错误。
3.区域性,更新对象的计数器,只是影响到该对象,不会扫描全部对象。
缺点:
1.每次对象被引用时,都需要去更新计数器,有一点时间开销。
2.浪费CPU资源,即使内存够用,仍然在运行时进行计数器的统计。
3.无法解决循环引用问题。(最大的缺点)
如果a和b两个对象存在相互引用,即使a和b都为null,a和b永远不会被回收。

标记清除法
标记:从根节点开始标记引用的对象
清除:未被标记引用的对象就是垃圾对象,可以被清理
优点:解决了引用计数器算法中的循环引用的问题,没有从root节点引用的对象都会被回收
缺点:
1.效率较低,标记和清除两个动作都需要遍历所有的对象,并且在GC时,需要暂停应用程序,对于交互性要求比较高的应用,体验非常差。
2.通过标记清除算法清理出的内存,碎片化比较严重,被回收的对象存在于内存的各个角落,所以清理出来的内存是不连贯的。

标记压缩算法
对标记清除算法做了优化,在清理阶段,将存活的对象压缩到内存的一端,然后清理边界以外的垃圾,解决了碎片化的问题。
优点:解决了碎片化的问题
缺点:标记压缩算法多了一步,对象移动内存位置,效率有一定的影响。

复制算法
将内存空间一分为二,每次用其中的一块,将正在使用的对象复制到另一个内存空间,清空该内存,交换内存的角色
优点:
①优秀的吞吐量
GC 标记 - 清除算法消耗的吞吐量是搜索活动对象(标记阶段)所花费的时间和搜索整体 堆(清除阶段)所花费的时间之和。

另一方面,因为 GC 复制算法只搜索并复制活动对象,所以跟一般的 GC 标记 - 清除算 法相比,它能在较短时间内完成 GC。也就是说,其吞吐量优秀。

尤其是堆越大,差距越明显。GC 标记 - 清除算法在清除阶段所花费的时间会不断增加, 但 GC 复制算法就不会产生这种消耗。毕竟它消耗的时间是与活动对象的数量成比例的。

②可实现高速分配
GC 复制算法不使用空闲链表。这是因为分块是一个连续的内存空间。比起 GC 标记 - 清除算法和引用计数法等使用空闲链表的分配,GC 复制算法明显快得多。

③不会发生碎片化
基于算法性质,活动对象被集中安排在 From 空间的开头对吧。像这 样把对象重新集中,放在堆的一端的行为就叫作压缩。在 GC 复制算法中,每次运行 GC 时 都会执行压缩。

因此 GC 复制算法有个非常优秀的特点,就是不会发生碎片化。也就是说,可以安排分 块允许范围内大小的对象。

缺点:
①堆使用效率低下
GC 复制算法把堆二等分,通常只能利用其中的一半来安排对象。也就是说,只有一半 堆能被使用。相比其他能使用整个堆的 GC 算法而言,可以说这是 GC 复制算法的一个重大的缺陷。

通过搭配使用 GC 复制算法和 GC 标记 - 清除算法可以改善这个缺点。

②递归调用函数
在这里介绍的算法中,复制某个对象时要递归复制它的子对象。因此在每次进行复制的 时候都要调用函数,由此带来的额外负担不容忽视。大家都知道比起这种递归算法,迭代算 法更能高速地执行

此外,因为在每次递归调用时都会消耗栈,所以还有栈溢出的可能。

破化双亲委派模型

https://blog.csdn.net/m0_37556444/article/details/81912283
什么情况下需要破坏双亲委派模型

静态代码块加载的时机

当类加载器将类加载到JVM中的时候就会创建静态变量,这跟对象是否创建无关。静态变量加载的时候就会分配内存空间。静态代码块的代码只会在类第一次初始化的时候执行一次。一个类可以有多个静态代码块,它并不是类的成员,也没有返回值,并且不能直接调用。静态代码块不能包含this或者super,它们通常被用初始化静态变量。

类只有在用到的时候才会被加载,并不是JVM一启动就加载。

什么是 java OOM?举例说明哪些场景会出现OOM?如何分析及解决 OOM 问题?

https://blog.csdn.net/weixin_42956047/article/details/103460093

如何实现一个自定义类加载器?

https://blog.csdn.net/qq_28605513/article/details/85014451

采用自动内存管理的好处和弊端

采用自动内存管理,不再需要为每一个new操作去写配对的delete/free代码,不容易出现内存泄漏和内存溢出问题。但是如果一旦出现内存泄漏和溢出方面的问题,如果不了解虚拟机是怎样使用内存的那排查错误、修正问题将变成一项异常艰难的问题。同时自动内存管理工作也是需要耗费一定的CPU和内存资源的。
  Java和C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外的人想进去,墙里的人想出来。

有什么方法来避免Full GC

避免频繁创建销毁大对象(运用单例模式)
把新生代空间调大
https://www.pianshen.com/article/44251818858/
通过打印GC日志来分析fullGC产生的原因,然后根据不同的原因来采取响应的措施。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值