身为一个java程序员如果只会使用而不知原理称其为初级java程序员,知晓原理而升中级、融会贯通则为高级

作为有一个有技术追求的人,应当利用业余时间及零碎时间了解原理

近期在看深入理解java虚拟机 第二版(基于jdk1.7)所以想写一些观后心得,整理一些比较重点的内容,也加强自己对重点内容的记忆!

以下默认虚拟机为hotsport虚拟机

一.jvm内存模型

① 程序计数器:

  程序计数器为每个线程私有

作用可以理解为在虚拟机解析字节码时记录当前字节码的行号

占用的内存较小

是唯一一个不会发生内存溢出(OOM)的区域


②虚拟机栈:

 虚拟机栈也是线程私有的

 虚拟机栈包括了java虚拟机栈以及本地方法栈,两者唯一的区别是前者是针对java后者是针对本地方法(本地方法可以理解为操作系统的方法)

 栈中的一个栈帧包含了一个方法中的局部变量、方法出口、操作数栈、动态链接等各种信息

需要注意栈中存储的只有基本数据类型以及引用类型变量,对象的内存分配都在堆中

每个栈帧的入栈到出栈对应着线程调用一个方法到方法执行结束

 栈的深度是动态扩展的

 当线程调用深度大于虚拟机允许的深度时(使用xss参数调整虚拟机栈内存容量)会发生StackOverflowError(SOF)异常

 栈帧的每次入栈会判断栈的内存容量是否足够,发现内存不足即会申请内存,当无法申请到足够的内存时会发生OutOfMemoryError(OOM)异常

 因为虚拟机栈严格遵守方法调用 入栈 方法执行结束 出栈 的规则,所以无需gc回收


③堆

 java堆为gc(Garbage Collecte11d) 回收的主要区域

 java堆被所有线程共享

 java堆存放着几乎所有的对象实例,它也只存放着对象实例

堆中分为年轻代,年老代

年轻代又被细分为Eden区和两个survivor区,该区的gc回收算法为复制算法,关于gc算法下文会讲到

 年轻代存储的都是新生不久的对象(未经过gc回收或者经过不多的gc回收,使用MaxTenuringThreshold参数设置经过几次gc后对象可以晋升到年老代)

 年老代存储的是一些占用内存较大的大对象(使用PertenureSizeThreshold参数设定这个内存界限值)或者经过数次gc后还存活的对象

还有一种情况,当Survivor区中同一年龄的所有对象大小总和大于Survivor区总内存的一半时,将大于等于该年龄的对象全部晋升年老代

 年老代因为存储大对象以及对象存活周期较长的特性,所以采用标记-整理算法

 当有对象实例化到堆中时,如果堆中无法提供连续的内存空间就会触发gc,而gc后仍无法分配足够的内存空间就会发生OOM异常


④方法区

 方法区被所有线程共享

 方法区存储着已加载的类信息、类的静态变量、常量等数据

 方法区包含了运行时常量池,其中包括了编译期生成的各种字面量和符号引用,并且运行时常量池可以在进程运行时动态增加数据

 方法区有些时候也和年轻代和老年代并称为永久代,但是其实方法区并不永久,方法区也有gc回收

 当常量池中的对象不存在任何引用时将被gc回收

 当一个类不存在任何实例、加载该类的classLoader 已经被回收、对应的java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法,才能被回收

 同样的当方法区无法满足内存分配需求时会发生OOM异常

二.gc策略以及gc算法

 在虚拟机栈以及程序计数器中因为栈帧入栈出栈的稳定性所以不需要过多考虑gc问题,这里主要对java堆中内存gc做讲解

 我们只需要明确三点就可以理解gc的过程

1.什么内存需要被回收

 2.什么时候回收

 3.怎样回收

 什么内存需要被回收:当然是已经不需要再用到的对象才需要被回收,如何判断这个对象已经无用?这里有两种判断算法一是引用计数算法,二是可达性分析算法,引用计算算法就是计算各个对象之间的引用关系数量java采用的是后者,所以前者这里不多做介绍

 

 可达性分析算法:使用一系列对象作为gc roots 也就是根节点遍历整个引用链,在引用链之外的对象既无用对象

 可以作为gc roots的对象如下:

    java虚拟机栈中引用的对象

    方法区中静态变量引用的对象

    方法区中常量引用的对象

    本地虚拟机栈中引用的对象


 这里需要注意引用这个概念,引用分为四种引用,四种引用排序从强至弱如下:

    强引用——所有New出来的对象都为强引用,引用链上的对象只要存在强引用即使发生OOM异常也无法被gc回收

    软引用——当系统即将发生内存溢出时,会优先回收掉软引用

    弱引用——当发生gc时直接回收弱引用

    虚引用——没有任何作用,虚引用甚至不能获取到对象实例,唯一作用是在对象被回收时会收到一个系统通知


 什么时候回收:大多数情况下对象都会分配在Eden区,而当Eden区内存不足时就会触发Minor Gc

   所以分配率越高,越频繁执行 Minor GC,Minor Gc 可以理解为只对年轻代进行Gc回收的策略。

   当年轻代Survivor空间不足,并且年老代所剩空间也无法为Surivivor承担时就会发生Full Gc 可以理解为对全部的堆进行Gc回收

   在大对象分配时老年代空间不足发生Full Gc

   在方法区进行类的装载或者常量池动态增加常量时方法区空间不足 发生Full  Gc


 怎样回收:

常见的三种gc算法:标记-清除、复制、标记整理

 标记-清除——先标记所有可用对象,再清除掉所有非可用对象

 复        制——划分出A、B两片内存空间,将所有数据 存在A区域中,当发生gc时将可用对象复制到B空间,然后一次清除A空间中所有内存,下一次gc则是重复B复制到A 再清除B空间内存

 标记-整理——标记所有可用对象,再将所有可用对象移动到一端,再一次性清除掉端界外的非可用对象

 结合年轻代以及年老代的性质分析各个区域的gc算法

 年  轻  代——因为年轻代Eden区对象绝大部分都是 “朝生夕死” 所以使用标记-清除或者标记-整理效率会很低,而使用效率高的复制算法又非常浪费空间,所以年轻代改进了复制算法,使用Eden区和两块Survivor区,因为Eden区一次gc存活下来的对象通常非常少,所以年轻代默认采用8:1:1的比例对Eden区和两块Survivor区进行内存分配,当发生gc时 将Eden区存活的对象和 一块Survivor区中存活的对象 复制到 另一块Survivor区中,然后清除掉Eden 区和第一块 Survivor区的内存,这样既保证了gc效率,又不至于会浪费大量的内存空间

 年  老  代——年老代因为存放大对象或者生命周期较长的对象,所以不能像年轻代一样使用复制算法,因为那样可能会导致大量的对象复制,导致效率极低,而这个时候标记-整理算法的优势体现出来,它只需要标记出 在年老代 为数不多的 非可用对象然后将非可用对象移动到堆的末端后一次性清除即可

深入学习重点分析java基础---第一章:深入理解jvm(java虚拟机) 第一节 java内存模型及gc策略的更多相关文章

  1. JAVA基础第二章-java三大特性:封装、继承、多态

    业内经常说的一句话是不要重复造轮子,但是有时候,只有自己造一个轮子了,才会深刻明白什么样的轮子适合山路,什么样的轮子适合平地! 我将会持续更新java基础知识,欢迎关注. 往期章节: JAVA基础第一 ...

  2. Java 内存模型及GC原理 (转)

      来源:http://blog.csdn.net/ithomer/article/details/6252552 一个优秀Java程序员,必须了解Java内存模型.GC工作原理,以及如何优化GC的性 ...

  3. 【转】Java 内存模型及GC原理

    一个优秀Java程序员,必须了解Java内存模型.GC工作原理,以及如何优化GC的性能.与GC进行有限的交互,有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只有全面提升内存的管理效率,才能 ...

  4. Java 内存模型、GC原理及算法

    Java 内存模型.GC原理:https://blog.csdn.net/ithomer/article/details/6252552 GC算法:https://www.cnblogs.com/sm ...

  5. Java 内存模型及GC原理 (转载)

    一个优秀Java程序员,必须了解Java内存模型.GC工作原理,以及如何优化GC的性能.与GC进行有限的交互,有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只有全面提升内存的管理效率,才能 ...

  6. Java 内存模型及GC原理

    一个优秀Java程序员,必须了解Java内存模型.GC工作原理,以及如何优化GC的性能.与GC进行有限的交互,有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只有全面提升内存的管理效率,才能 ...

  7. JAVA基础01----第1章Java开发环境搭建

    一. Java开发环境中涉及的名词:JDK,JRE,JVM A:什么是JVM JVM是java虚拟机(JVM Java Virtual Machine),java程序需要运行在虚拟机上,不同平台有自己 ...

  8. Java基础12:深入理解Class类和Object类

    更多内容请关注微信公众号[Java技术江湖] 这是一位阿里 Java 工程师的技术小站,作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux ...

  9. Java基础教程(12)--深入理解类

    一.方法的返回值   当我们在程序中调用方法时,虚拟机将会跳转到对应的方法中去执行.当以下几种情况发生时,虚拟机将会回到调用方法的语句并继续向下执行: 执行完方法中所有的语句: 遇到return语句: ...

随机推荐

  1. 渗透测试平台Vulnreport介绍与使用

    渗透测试平台Vulnreport介绍与使用   在这篇文章中,我们将跟大家讨论一些关于渗透测试方面的内容,并给大家介绍一款名叫Vulnreport的新型开源工具,而这款工具将能够让任何场景下的渗透测试 ...

  2. JavaScript在页面中的执行顺序(理解声明式函数与赋值式函数) 转载

    JavaScript在页面中的执行顺序 https://blog.csdn.net/superhoy/article/details/52946277 2016年10月27日 15:38:52 阅读数 ...

  3. 4.NIO_Channel 通道

    1.通道(Channel) 由 java.nio.channels 包定义的.Channel 表示 IO 源与目标打开的连接.Channel 类似于传统的“流”.只不过 Channel 本身不能直接访 ...

  4. [转载]Spark-Task not serializable错误解析

    Spark-Task not serializable错误解析 2018年05月17日 15:33:03 沙拉控 阅读数:1509   在学习SparkStreaming的时候偶然出现的一个问题,先看 ...

  5. 浅谈响应式Web设计与实现思路

    是否还在为你的应用程序适配PC端,移动端,平板而苦苦思索呢,是否在寻找如何一套代码适配多终端方式呢,是否希望快速上手实现你的跨终端应用程序呢,是的话,那就看过来吧,本文阐述响应式UI设计相关理论基础, ...

  6. 关于RedisTemplate和StringRedisTemplate(转)

    最近在开始在学习Redis以及如何在Java当中去使用Redis,Redis是什么我这里就不说了. 我主要想说的是Redis和Java当中Spring结合起来的时候,使用到的RedisTemplate ...

  7. JMeter性能测试,完整入门篇(转)

    原文转自:https://blog.csdn.net/lovesoo/article/details/78579547 Apache JMeter是一款纯java编写负载功能测试和性能测试开源工具软件 ...

  8. ZAP笔记

    1.HTTP自动变成HTTS问题. 在使用OWASP ZAP 2.8.0的时候,如果设置了dynamic ssl certificates,并把正式导入到浏览器的时候 如果ZAP当做代理访问HTTP的 ...

  9. 使用CSS3 will-change提高页面滚动、动画等渲染性能----------------------------引用

    Chris Ruppel当其使用background-attachment: fixed实现背景图片不随滚动条滚动而滚动效果的时候, 大家肯定会好奇,这到底施了什么魔法,可以让渲染提升如此之显著.3个 ...

  10. Https Get Post

    #region Http 访问 public string GetHttpUrl(string Url) { try { HttpWebRequest request = (HttpWebReques ...