Java开发有个很基础的问题,虽然我们平时接触的不多,但是了解它却成为Java开发的必备基础——这就是JVM。在C++中我们需要手动申请内存然后释放内存,否则就会出现对象已经不再使用内存却仍被占用的情况。在Java中JVM内置了垃圾回收的机制,帮助开发者承担对象的创建和释放的工作,极大的减轻了开发的负担。那是不是我们就不需要了解JVM了,显然在做一些优化或者深入研究应用性能的时候,JVM还是起了很关键的作用的。因此本篇就总结性的描述下JVM的内存模型与垃圾回收相关的知识。

本文的主要内容如下:

  • 内存模型
  • 垃圾回收
  • 参考文章

内存模型

各部分的功能

这几个存储区最主要的就是栈区和堆区,那么什么是栈什么是堆呢?说的简单点,栈里面存放的是基本的数据类型和引用,而堆里面则是存放各种对象实例的。

堆与栈分开设计是为什么呢?

  • 栈存储了处理逻辑、堆存储了具体的数据,这样隔离设计更为清晰
  • 堆与栈分离,使得堆可以被多个栈共享。
  • 栈保存了上下文的信息,因此只能向上增长;而堆是动态分配

栈的大小可以通过-XSs设置,如果不足的话,会引起java.lang.StackOverflowError的异常

栈区

线程私有,生命周期与线程相同。每个方法执行的时候都会创建一个栈帧(stack frame)用于存放 局部变量表、操作栈、动态链接、方法出口。

存放对象实例,所有的对象的内存都在这里分配。垃圾回收主要就是作用于这里的。

  • 堆得内存由-Xms指定,默认是物理内存的1/64;最大的内存由-Xmx指定,默认是物理内存的1/4。
  • 默认空余的堆内存小于40%时,就会增大,直到-Xmx设置的内存。具体的比例可以由-XX:MinHeapFreeRatio指定
  • 空余的内存大于70%时,就会减少内存,直到-Xms设置的大小。具体由-XX:MaxHeapFreeRatio指定。

因此一般都建议把这两个参数设置成一样大,可以避免JVM在不断调整大小。

程序计数器

这里记录了线程执行的字节码的行号,在分支、循环、跳转、异常、线程恢复等都依赖这个计数器。

方法区

类型信息、字段信息、方法信息、其他信息

总结

名称 特征 作用 配置 异常
栈区 线程私有,使用一段连续的内存空间 存放局部变量表、操作栈、动态链接、方法出口 -XSs StackOverflowError OutOfMemoryError
线程共享,生命周期与虚拟机相同 保存对象实例 -Xms -Xmx -Xmn OutOfMemoryError
程序计数器 线程私有、占用内存小 字节码行号
方法区 线程共享 存储类加载信息、常量、静态变量等 -XX:PermSize -XX:MaxPermSize OutOfMemoryError

垃圾回收

如何定义垃圾

有两种方式,一种是引用计数(但是无法解决循环引用的问题);另一种就是可达性分析。

判断对象可以回收的情况:

  • 显示的把某个引用置位NULL或者指向别的对象
  • 局部引用指向的对象
  • 弱引用关联的对象

垃圾回收的方法

Mark-Sweep标记-清除算法

这种方法优点就是减少停顿时间,但是缺点是会造成内存碎片。

Copying复制算法

这种方法不涉及到对象的删除,只是把可用的对象从一个地方拷贝到另一个地方,因此适合大量对象回收的场景,比如新生代的回收。

Mark-Compact标记-整理算法

这种方法可以解决内存碎片问题,但是会增加停顿时间。

Generational Collection 分代收集

最后的这种方法是前面几种的合体,即目前JVM主要采取的一种方法,思想就是把JVM分成不同的区域。每种区域使用不同的垃圾回收方法。

上面可以看到堆分成两个个区域:

  • 新生代(Young Generation):用于存放新创建的对象,采用复制回收方法,如果在s0和s1之间复制一定次数后,转移到年老代中。这里的垃圾回收叫做minor GC;
  • 年老代(Old Generation):这些对象垃圾回收的频率较低,采用的标记整理方法,这里的垃圾回收叫做 major GC。

这里可以详细的说一下新生代复制回收的算法流程:

在新生代中,分为三个区:Eden, from survivor, to survior。

  • 当触发minor GC时,会先把Eden中存活的对象复制到to Survivor中;
  • 然后再看from survivor,如果次数达到年老代的标准,就复制到年老代中;如果没有达到则复制到to survivor中,如果to survivor满了,则复制到年老代中。
  • 然后调换from survivor 和 to survivor的名字,保证每次to survivor都是空的等待对象复制到那里的。

垃圾回收器

串行收集器 Serial

这种收集器就是以单线程的方式收集,垃圾回收的时候其他线程也不能工作。

并行收集器 Parallel

以多线程的方式进行收集

并发标记清除收集器 Concurrent Mark Sweep Collector, CMS

大致的流程为:初始标记--并发标记--重新标记--并发清除

G1收集器 Garbage First Collector

大致的流程为:初始标记--并发标记--最终标记--筛选回收

参考

作者:xingoo
本文版权归作者和博客园共有。欢迎转载,但必须保留此段声明,且在文章页面明显位置给出原文连接!

JVM内存模型和垃圾回收的更多相关文章

  1. 程序猿的日常——JVM内存模型与垃圾回收

    Java开发有个很基础的问题,虽然我们平时接触的不多,但是了解它却成为Java开发的必备基础--这就是JVM.在C++中我们需要手动申请内存然后释放内存,否则就会出现对象已经不再使用内存却仍被占用的情 ...

  2. 【Java_基础】JVM内存模型与垃圾回收机制

    1. JVM内存模型 Java虚拟机在程序执行过程会把jvm的内存分为若干个不同的数据区域来管理,这些区域有自己的用途,以及创建和销毁时间. JVM内存模型如下图所示 1.1 程序计数器 程序计数器( ...

  3. JVM的stack和heap,JVM内存模型,垃圾回收策略,分代收集,增量收集

    (转自:http://my.oschina.net/u/436879/blog/85478) 在JVM中,内存分为两个部分,Stack(栈)和Heap(堆),这里,我们从JVM的内存管理原理的角度来认 ...

  4. JVM内存模型,垃圾回收算法

    JVM内存模型总体架构图 程序计数器多线程时,当线程数超过CPU数量或CPU内核数量,线程之间就要根据时间片轮询抢夺CPU时间资源.因此每个线程有要有一个独立的程序计数器,记录下一条要运行的指令.线程 ...

  5. JVM内存模型以及垃圾回收

    JAVA堆的描述如下: 内存由Perm和Heap组成.其中Heap = {Old + NEW = { Eden , from, to } } JVM内存模型中分两大块: NEW Generation: ...

  6. JVM内存模型及垃圾回收算法

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...

  7. JVM内存模型及垃圾回收的研究总结

    Java内存模型 总的来说就分为两个区域,堆内存(Heap)和非堆内存(No-Heap),非堆内存又称为永久代(Permanent),永久的意思其实是针对于垃圾回收器来说的,表示这部分内容不需要回收. ...

  8. JVM内存模型与垃圾回收

    内存模型 1,程序计数器(Program Counter Register):程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行到了第几行,可以理解为是当前线程的行号指示器.字节码解 ...

  9. JVM 内存模型及垃圾回收

    java内存模型 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地方法栈五个部分. 程序计数器:程序计数器是指CPU中的寄存器,它保存的是程序当前执行的指令的地址(也可以说 ...

随机推荐

  1. jenkins任务构建失败重试插件Naginator Plugin

    jenkins任务失败重新构建插件Naginator Plugin jenkins任务经常会因为一些偶然因素失败,这时重新构建一次就肯能成功:jenkins的Naginator Plugin插件可以重 ...

  2. 不写代码也能爬虫Web Scraper

    https://www.jianshu.com/p/d0a730464e0c web scraper中文网 http://www.iwebscraper.com/category/%E6%95%99% ...

  3. “全栈2019”Java异常第六章:finally代码块作用域详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  4. docker的介绍以及常用命令

    一.docker的介绍 1. Docker是什么? Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚 ...

  5. OWASP JUICE SHOP部分题解

    本文作者:S0u1 0×00 简介 OWASP JUICE SHOP是一个开源的web应用靶场,里面包含了共记47个漏洞挑战任务,囊括了OWASP TOP 10的各个点,是一个很不错的渗透测试练手项目 ...

  6. C#控制台输出退格实现变换闪烁的字符效果

    C#控制台输出退格实现变换闪烁的字符效果,传统的Console.Clear()方法能清除控制台上的所有内容. 如果用 Console.Write('\u0008');可以实现输出退格,这样就可以方便地 ...

  7. linux centos 7 下安装ElasticSearch5.4

    一. 把elasticsearch-5.4.0.rpm和kibana-5.4.0-x86_64.rpm上传到centos下/root目录中,如下图:二.进入centos目录/root,并用命令rpm ...

  8. jmeter 之 BeanShell PostProcessor跨线程全局变量使用

    BeanShell PostProcessor是用户对一些变量的操作,操作方法很灵活,大概原理是通过parameters传回来对象,然后在script中对对象进行操作 场景:从登陆接口中获取token ...

  9. 有向图的拓扑排序的理解和简单实现(Java)

    如果图中存在环(回路),那么该图不存在拓扑排序,在这里我们讨论的都是无环的有向图. 什么是拓扑排序 一个例子 对于一部电影的制作过程,我们可以看成是一个项目工程.所有的工程都可以分为若干个" ...

  10. Linux(ubuntu18.04)切换python版本

    前言 Ubuntu18.04系统在安装python时会安装两个版本:2.7和3.6.默认情况下系统环境使用的是python2,但是我们有时需要使用python3来作为我们的开发环境,所以需要自由切换p ...