身为一个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. JAVA程序员成长路线图

    https://www.cnblogs.com/godtrue/p/4283708.html

  2. ubuntu配置jdk(收藏)

    ubuntu下JDK配置本质上和win是一样的: 1.去官网下载JDK7,找jdk-7u21-linux-i586.tar.gz并下载:http://www.oracle.com/technetwor ...

  3. linux TAILQ_ENTRY

    #include <sys/queue.h> TAILQ_ENTRY 队列 http://www.360doc.com/content/15/1222/14/29292169_522271 ...

  4. Linux/Centos查看进程占用内存大小的几种方法总结

    1.命令行输入top回车,然后按下大写M按照memory排序,按下大写P按照CPU排序. 2. ps -ef | grep "进程名"     ps -e -o 'pid,comm ...

  5. No valid Maven installation found. Either set the home directory in the configuration dialog or set

    原因: IDEA的maven地址设置出错,系统找不到指定的maven路径 解决: setting---->maven修改正确的maven链接地址. 设置你maven 的地址为你的存放路基就好了

  6. 生产问题之StackOverflowError异常小记

    印象中,这是项目中首次遇到 StackOverflowError,在此做个笔记. (吃饭回来写) …… 吃饭回来后,尝试把代码回退来分析异常产生原因,然而却无法复现这个栈溢出异常……醉了 有缘再见再写 ...

  7. python中的apply(),applymap(),map() 的用法和区别

    平时在处理df series格式的时候并没有注意 map和apply的差异 总感觉没啥却别.不过还是有区别的.下面总结一下: import pandas as pd df1= pd.DataFrame ...

  8. 使用python脚本进行数据清洗(1)

    1. 原始表 CREATE TABLE ml_100k (userid INT, movieid INT, rating INT, unixtime STRING) ROW FORMAT DELIMI ...

  9. [Git] How to revert one file changes from one commit

    Many times we might changed one file which we don't intent to do... but it was too late, until we fo ...

  10. React组件(组件属性this.state和this.props,css样式修饰组件)

    目录: 1.创建组件的第一种方式 function2.将组件抽离为单独的jsx文件3.省略.jsx后缀, 配置webpack设置根目录4.创建组件的第二种方式--使用class关键字创建组件5.组件私 ...