JAVA的内存回收机制(快速入门版)

2023-11-04

java内存回收机制

内存回收,是JVM中垃圾回收器提供的一种用于在空闲时间不定时回收无任何对象引用的对象占据的内存空间的一种机制

引用 :

java中什么是引用?

Person xiaoi =new Person();

new person()以person类为模板,创建一个person类的对象,括号代表对象创建后,立刻调用person类的构造函数,并对该对象进行初始化。左边的person xiaoi就是创建了一个peeson类的引用变****量,用来指向person对象的对象引用

​ 如果reference类型的数据存储的数值代表的是另一块内存的地址,就称这块内存代表着一个引用

强引用

​ 就像Object object =new Object() 这类引用是Java程序中最普遍的,只要强引用还在 垃圾回收器就永远不会回收掉被 引用的对象

软引用

soft reference 描述一些可能还有用,非必须的对象。 系统内存不够的时候,这类引用关联的对象将被垃圾收集器回收 jdk1.2之后提供了soft reference类来实现软引用

弱引用

weak reference 用来描述比软引用更弱,只能活到垃圾回收器到来之前,jdk1.2之后提供了weak reference类实现弱引用

虚引用

最弱,为一个对象设置虚引用是为了在被垃圾收集器回收的时候收到一个通知

怎么判断垃圾

1 引用计数算法

每个对象都有一个引用计数器,当对象被创建并赋初始值之后,变量计数为1,每当一个地方引用他就+1 引用失效就-1,等于0就会被垃圾收集

​ 优点:简单,执行率高

​ 缺点: 没办法检测出对象中的循环引用,同时计数器增加程序开销

2根搜索算法

根集就是正在执行的java程序可以访问的引用变量的集合(包括局部变量,参数,类变量

程序可以使用引用变量访问对象的属性和调用对象的方法

基本思路是

1 通过一系列名为gc roots的对象作为起始点,寻找对应的引用节点

找到这些引用节点后 从这些节点向下开始寻找他们的引用节点

​ 重复上一步

​ 搜索走过的路径称之为引用链,当一个对象到gc roots没有任何引用链链相连时候,就说明这个对象是不可用的

gcroot

​ 包括虚拟机栈中引用的对象 方法区中常量引用的对象 方法区中的类静态属性引用的对象 本地方法中jni的引用对象 活跃的线程

标记注意点

标记前要暂停应用线程 这种暂停线程的做法叫安全点safe point 常见出现安全点的原因就是垃圾回收

暂停时间的长短取决于存活对象的多少

根搜索算法中 要经历两次标记过程才会宣告一个对象的死亡

​ 第一次标记----进行一次筛选(筛选条件:是否有必要执行finalize方法)

​ 有必要执行的–进入队列—进行第二次筛选(筛选条件:是否通过finalize方法中重新进入引用链)

finalize方法

​ 目的是在对象不在被需要 将被丢弃之前执行清除操作(例如输入输出连接的对象可能会在丢弃之前断开连接操作)

回收垃圾的算法

1 标记-清除算法

使用根集的概念,标记出所有回收的对象 标记完成后统一回收

优点:

不需要对象移动,存活对象多的时候极为高效

缺点

效率不高

会产生大量不连续的内存碎片,引发第二次垃圾回收

2标记-整理

标记后将所有对象向一边移动,然后清理掉边界之外的内存

优点

新对象的分配只要通过指针碰撞就能完成(指针碰撞,有个指针作为空闲与否的分界线,那么为新对象分配内存空间只需要指针往后加需要的大小就可以)

缺点

gc暂停时间延长(要把所有的对象拷贝到新的地方)

3copying算法

将内存分为两半,一块用完了,就将还存活着对象复制到另外一块内存上,直接清理掉另一块内存

优点

标记和复制阶段同时进行

每次只要回收一半(一块的内存) 效率高

分配内存方便,移动栈顶指针即可

内存回收不需要考虑内存碎片的出现

缺点

一次性可以分配的最大内存缩小了一半

如果活着的对象很多,复制就会很费性能(比如在老年代中的对象,生存期很长) 比较适合活着的对象很短的新生代

adaptive算法

根据堆的使用情况来选择合适的算法

java堆内存分配区域

年轻代

新生成对象存放处, 分成 eden servicor1 和servivor0区 分配比例8.1.1

当eden满,触发一次gc,将eden区存活的对象放到ser0,清空eden

如果ser0满就存到1,然后清空eden和ser0

如果1也满了,存活的对象会直接进入老年代

如果一个对象躲过1次gc 年龄gc 如果大于设置好的年龄(默认15) 就会进入老年代

如果老年代也满了会触发一次全gc 这样会让老年代新生代都进行回收

年轻代大部分的对象都会很快死去,因此minor gc很频繁,可以用复制算法

老年代

存放的都会生命周期较长的对象 内存比例也会高很多,同时一些大对象会直接分配到老年代

由于都是生命周期长 对象 用复制算法会浪费时间,因此使用标记清除算法会好很多

持久代

存放静态文件 在javase8后变了元空间

垃圾回收器的类型

串行垃圾回收器

单线程回收,冻结所有应用程序,不适合服务器环境

并行垃圾回收器

多线程回收,一样会冻结所有应用程序,适合多cpu 对暂停时间要求较短的

并发标记扫描垃圾回收器

多线程扫描堆内存,使用更多的cpu进行,只有一些特殊情况才会冻结所有应用程序

G1垃圾回收器

最先进的收集器,面向服务端,充分利用多cpu多核环境 可以并行并发收集 适合于很大堆内存的情况

垃圾回收的执行时间

GC分为Scavenge GC和Full GC。

Scavenge GC :发生在Eden区的垃圾回收。

Full GC :对整个堆进行整理,包括Young、Tenured和Perm。Full GC因为需要对整个堆进行回收,所以比Scavenge GC要慢,因此应该尽可能减少Full GC的次数。在对JVM调优的过程中,很大一部分工作就是对于FullGC的调节。

1.年老代(Tenured)被写满;

2.持久代(Perm)被写满;

3.System.gc()被显示调用;

4.上一次GC之后Heap的各域分配策略动态变化.

。触发主gc的条件

1程序空闲(线程优先级最低,忙的时候不出现

2堆内存满了 (一次gc不行就两次gc 两次不行报oom)

减少gc开销的措施

1 不要显式调用system.gc();

2 减少临时对象的使用

3 不用的对象最好显式置为null

4 尽量使用stringbuffer而不是string进行字符拼接 (string累加会生成很多垃圾对象)

5尽量使用基本类型(包装类型占用资源)

6 少使用静态变量

7 分散对象创建或者删除的时间

GC性能调优

下次再讲

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JAVA的内存回收机制(快速入门版) 的相关文章

  • Oracle Java 教程 - 回答问题时可能出现错误

    我是 Java 新手 正在阅读 Oracle 教程 每个部分之后都有问题和答案 我不明白一个答案中的一句话 见下面的粗体线 来源是https docs oracle com javase tutorial java javaOO QandE
  • 如何强制jar使用(或jar运行的jvm)utf-8而不是系统的默认编码

    我的Windows默认编码是GBK 而我的Eclipse完全是utf 8编码 因此 在我的 Eclipse 中运行良好的应用程序崩溃了 因为导出为 jar 文件时这些单词变得不可读 我必须在 bat 文件中写入以下行才能运行该应用程序 st
  • Base36 编码字符串?

    我一直在网上查找 但找不到解决此问题的方法 在 Python Ruby 或 Java 中 如何对以下字符串进行 Base 36 编码 nOrG9Eh0uyeilM8Nnu5pTywj3935kW 5 Ruby 以 36 为基数 s unpa
  • 如何将jscrollpane添加到jframe?

    我有以下源代码 有人可以给我建议如何将 jscrollpane 添加到 jframe 上吗 我尝试了几次将其添加到 jframe 但没有任何进展 它甚至没有显示 public class Form3 JFrame jframe new JF
  • 埃拉托色尼筛法 - 实现返回一些非质数值?

    我用 Java 实现了埃拉托斯特尼筛法 通过伪代码 public static void sieveofEratosthenes int n boolean numArray numArray new boolean n for int i
  • 从 MS Access 中提取 OLE 对象(Word 文档)

    我有一个 Microsoft Access 数据库 其中包含一个包含 Microsoft Word 文档的 OLE 对象字段 我试图找到代码来检索保存在 OLE 对象中的文件 以便用户可以从我的 JavaFx 应用程序中的按钮下载它 但没有
  • 为什么Iterator接口没有add方法

    In IteratorSun 添加了remove 方法来删 除集合中最后访问的元素 为什么没有add方法来向集合中添加新元素 它可能对集合或迭代器产生什么样的副作用 好的 我们开始吧 设计常见问题解答中明确给出了答案 为什么不提供 Iter
  • Java:从集合中获取第一项

    如果我有一个集合 例如Collection
  • 从休眠乐观锁定异常中恢复

    我有一个这样的方法 Transactional propagation Propagation REQUIRES NEW public void doSomeWork Entity entity dao loadEntity do some
  • 当 minifyEnabled 为 true 时 Android 应用程序崩溃

    我正在使用多模块应用程序 并且该应用程序崩溃时minifyEnabled true in the installed模块的build gradle 以下是从游戏控制台检索到的反混淆堆栈跟踪 FATAL EXCEPTION Controlle
  • 寻找局部最小值

    下面的代码正确地找到了数组的局部最大值 但未能找到局部最小值 我已经进行了网络搜索 以找到找到最小值的最佳方法 并且根据这些搜索 我认为我正在使用下面的正确方法 但是 在几天的时间里多次检查每一行之后 下面的代码中有一些我仍然没有看到的错误
  • Karaf / Maven - 无法解决:缺少需求 osgi.wiring.package

    我无法在 Karaf 版本 3 0 1 中启动捆绑包 该包是使用 Maven 构建的并导入gson http mvnrepository com artifact com google code gson gson 2 3 1 我按照要求将
  • 如何让 Emma 或 Cobertura 与 Maven 一起报告其他模块中源代码的覆盖率?

    我有一个带有 Java 代码的多模块 Maven 设置 我的单元测试在其中一个模块中测试多个模块中的代码 当然 这些模块具有相互依赖性 并且在测试执行之前根据需要编译所有相关模块中的代码 那么 如何获得整个代码库覆盖率的报告 注意 我不是问
  • 禁用 Android 菜单组

    我尝试使用以下代码禁用菜单组 但它不起作用 菜单项仍然启用 你能告诉我出了什么问题吗 资源 菜单 menu xml menu menu
  • 如何处理 StaleElementReferenceException

    我正在为鼠标悬停工作 我想通过使用 for 循环单击每个链接来测试所有链接的工作条件 在我的程序中 迭代进行一次 而对于下一次迭代 它不起作用并显示 StaleElementReferenceException 如果需要 请修改代码 pub
  • Hadoop NoSuchMethodError apache.commons.cli

    我在用着hadoop 2 7 2我用 IntelliJ 做了一个 MapReduce 工作 在我的工作中 我正在使用apache commons cli 1 3 1我把库放在罐子里 当我在 Hadoop 集群上使用 MapReduceJob
  • 替换文件中的字符串

    我正在寻找一种方法来替换文件中的字符串而不将整个文件读入内存 通常我会使用 Reader 和 Writer 即如下所示 public static void replace String oldstring String newstring
  • ECDH使用Android KeyStore生成私钥

    我正在尝试使用 Android KeyStore Provider 生成的私有文件在 Android 中实现 ECDH public byte ecdh PublicKey otherPubKey throws Exception try
  • Java 的 PriorityQueue 与最小堆有何不同?

    他们为什么命名PriorityQueue如果你不能插入优先级 它看起来与堆非常相似 有什么区别吗 如果没有区别那为什么叫它PriorityQueue而不是堆 默认的PriorityQueue是用Min Heap实现的 即栈顶元素是堆中最小的
  • try-with-resources 中出现死代码警告,但翻译后的 try-catch-finally 中没有出现死代码警告

    以下代码使用try 有资源 https docs oracle com javase specs jls se7 html jls 14 html jls 14 20 3Java 8 中引入的构造 偶尔抛出 方法被声明为抛出一个偶尔的异常

随机推荐