《深入理解Java虚拟机》读后总结
基于Sun HotSpot JVM
请先了解JVM内存模型在来看此篇文章
使用对JVM不同内存区域灌入数据,导致相关区域内存溢出,来验证JVM内存分配
先看一个经典问题:
String s1 = "小金子(aub)"; String s2 = "小金子(aub)"; String s3 = "小金子" + "(aub)"; String s4 = new String("小金子(aub)"); String s5 = "小金子" + new String("(aub)"); String s6 = s4.intern(); System.out.println("s1 == s2: " + (s1 == s2));//true; System.out.println("s1 == s3: " + (s1 == s3));//true; System.out.println("s2 == s3: " + (s2 == s3));//true; System.out.println("s1 == s4: " + (s1 == s4));//false; System.out.println("s1 == s5: " + (s1 == s5));//false; System.out.println("s4 == s5: " + (s4 == s5));//false; System.out.println("s1 == s6: " + (s1 == s6));//true;
原因就在与String对象特殊的内存分配方式:(Strings pool是JVM内存中运行时常量池的一部分)
1.String s1 = new String("小金子(aub)");
2.String s2 = "小金子(aub)";
3.String s3 = "小金子" + "(aub)";
虽然两个语句都是返回一个String对象的引用,但是jvm对两者的处理方式是不一样的。
对于第一种,jvm会马上在heap中创建一个String对象,然后将该对象的引用返回给用户。
对于第二种,jvm首先会在内部维护的strings pool中通过String的 equels 方法查找是对象池中是否存放有该String对象,如果有,则返回已有的String对象给用户,而不会在heap中重新创建一个新的String对象;如果对象池中没有该String对象,jvm则在heap中创建新的String对象,将其引用返回给用户,同时将该引用添加至strings pool中。
注意:使用第一种方法创建对象时,jvm是不会主动把该对象放到strings pool里面的,除非程序调用 String的intern方法
对于第三种,jvm会进行“+”运算符号的优化,两遍都是字符串常量会做类似于第二种的处理,如果“+”任意一边是一个变量,就会做类似第一种的处理。
JVM栈和Native Method栈内存分配:
JAVA中八个基本类型数据,在运行时都是分配在栈中的。在栈上分配的内存,随着数据的进栈出栈,方法运行完毕,或则线程结束时,自动被回收掉了。
测试代码如下:
public class JvmStackOOM { private int stackLength = 1; public void execute() { try { stackLeak(); } catch (Throwable e) { System.out.println("stackLength : " + stackLength); e.printStackTrace(); } } private void stackLeak() { stackLength++; stackLeak(); } }
用一个递归不断地对实例变量stackLength进行自增操作,当JVM在扩展栈时无法申请到足够的空间,将产生StackOverflowError
可以使用Jvm 参数-Xss配置栈大小,例如:-Xss2M,栈内存越大,可的栈深度越大,在内存不变的情况下,jvm可创建的线程就越少,需要合理设置。
方法区内存分配:
类信息和运行时常量将会分配到此区域。
测试代码如下:
public class JvmRuntimeConstantPoolOOM { private int runtimeConstantCount = 1; public void execute() { try { runtimeConstantLeak(); } catch (Throwable e) { System.out.println("runtimeConstantCount : " + runtimeConstantCount); e.printStackTrace(); } } private void runtimeConstantLeak() { List<String> list = new ArrayList<String>(); while (true) { list.add(String.valueOf(runtimeConstantCount++).intern()); } } }
使用String的intern()方法向方法区中灌入数据,当方法区内存不足时,抛出OutOfMemoryError: PermGen space,
也可以加载过多的类的方式,测试是否有OutOfMemoryError: PermGen space异常,如果有说明类信息也是存放在方法区中的可以
使用Jvm 参数-XX:PermSize和-XX:MaxPermSize配置栈大小,例如:-XX:PermSize=10M -XX:MaxPermSize=10M
堆内存分配:
所有对象实例及数组都会在堆上分配。
堆分为新生代和老年代。新生代分为3个区域:一个eden区,和两个survivor区(互为From、To,相对的),
新建对象时首先想eden区申请分配空间,如果空间够,就直接进行分配,否则进行一次Minor GC(新生代垃圾回收)。
Minor GC后再次尝试将对象放到eden区,如果空间仍然不够,直接在老年代创建对象。
测试代码如下:
public class JvmHeapOOM { private int bojectCount = 1; public void execute() { try { heapLeak(); } catch (Throwable e) { System.out.println("bojectCount : " + bojectCount); e.printStackTrace(); } } private void heapLeak() { List<OOMObject> list = new ArrayList<OOMObject>(); while (true) { list.add(new OOMObject()); bojectCount++; } } private class OOMObject { } }
创建多个OOMObject对象放到List中,当堆内存不足时,产生OutOfMemoryError:Java Heap space
使用Jvm 参数-Xm -Xmx -Xmn -XX:SurvivorRatio配置堆,例如:-Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8
本地直接内存分配:
堆外内存,NIO相关操作将在此分配内存
使用Jvm 参数-XX:MaxDirectMemorySize配置,例如:-XX:MaxDirectMemorySize=10M
所有用到的JVM启动参数:
-Xss2M 设置JVM栈内存大小
-Xms20M 设置堆内存初始值
-Xmx20M 设置堆内存最大值
-Xmn10M 设置堆内存中新生代大小
-XX:SurvivorRatio=8 设置堆内存中新生代Eden 和 Survivor 比例
-XX:PermSize=10M 设置方法区内存初始值
-XX:MaxPermSize=10M 设置方法区内存最大值
-XX:MaxDirectMemorySize=10M 设置堆内存中新生代大小
原创文章,转载请指明出处:http://aub.iteye.com/blog/1872936
相关推荐
深入理解java虚拟机视频教程,jvm原理,java虚拟机,jvm性能调优,内存模型,gc工作原理,内存分配,类的加载等等视频教程
1. JVM调优 1.1 JVM调优总结(一)-一些概念 1.2 JVM调优总结(二)-一些概念 1.3 JVM调优总结(三)-基本垃圾回收算法 1.4 JVM调优总结(四)-垃圾...4.2 JVM内存管理:深入垃圾收集器与内存分配策略 4.3 深入理解JVM
第31节深入理解对象的访问定位00:08:01分钟 | 第32节垃圾回收-概述00:06:20分钟 | 第33节垃圾回收-判断对象是否存活算法-引用计数法详解00:14:08分钟 | 第34节垃圾回收-判断对象是否存活算法-可达性分析法详解00:...
包括jvm 的内存模型 对象的创建过程 垃圾回收算法 垃圾回收器 内存分配和回收策略
/ 57 3.4.3 Parallel Scavenge收集器 / 59 3.4.4 Serial Old收集器 / 60 3.4.5 Parallel Old收集器 / 61 3.4.6 CMS收集器 / 61 3.4.7 G1收集器 / 64 3.4.8 垃圾收集器参数总结 / 64 3.5 内存分配与回收策略 /...
2019最新深入理解JVM内存结构及运行原理(JVM调优)高级核心课程视频教程下载。JVM是Java知识体系中的重要部分,对JVM底层的了解是每一位Java程序员深入Java技术领域的重要因素。本课程试图通过简单易懂的方式,系统...
2019最新深入理解JVM内存结构及运行原理(JVM调优)高级核心课程视频教程下载。JVM是Java知识体系中的重要部分,对JVM底层的了解是每一位Java程序员深入Java技术领域的重要因素。本课程试图通过简单易懂的方式,系统...
* 在内存结构章节,能够学习掌握 JVM内存溢出现象,堆栈内存结构,利用内存诊断工具排查问题。彻底分析 StringTable的相关知识与性能优化,掌握直接内存分配原理和释放手段。 * 在垃圾回收章节,不仅会介绍垃圾回收...
这本书的内容是帮你全面了解java虚拟机,本书第1版两年内印刷近10次,98%以上的评论全部为5星级的好评,是整个Java图书领域公认的经典著作和超级畅销书,繁体版在台湾也十分受欢迎。第2版在第1版的基础上做了很大的...
按照官方的说法:Java虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。 JVM主要管理两种类型内存:堆和非堆,堆内存(HeapMemory)是在Java虚拟机启动时创建,非堆内存(Non-heap ...
深入理解Java虚拟机 Java内存区域划分与对象新建过程 jvm垃圾收集机制与内存分配策略 jvm类加载机制 Java的内存模型 锁优化 Think In Java Java容器 Java并发 Java Concurrency in Practice 对象的共享 对象的组合 ...
JVM的重要性不言而喻,这个是学习JVM是看视频和读《深入理解JVM》时做的一些笔记,用于复习参考。 读书笔记 第2章:java内存模型和内存溢出异常 1.运行时数据区域 1.程序计数器:线程私有 2.java虚拟机栈:线程私有...
学生提问:不是说JVM是运行Java程序的虚拟机吗?那JRE和JVM的关系是怎样的呢? 8 学生提问:为什么不安装公共JRE系统呢? 9 1.4.2 设置PATH环境变量 10 学生提问:为什么选择设置用户变量,用户变量和系统变量有...
│ │ 深入理解Java内存模型.pdf │ │ │ └─课后资料 │ ├─笔记 │ │ 淘淘商城_day20_课堂笔记.docx │ │ │ └─视频 │ 07-使用Jedis连接集群操作.avi │ 00-今日大纲.avi │ 01-RDB持久化方式.avi │ 02...