第一部分-jvm内存结构

jre与jdk的区别

jre, java runtime enviriment,运行java程序的环境(普通用户)
jdk, java develop kite, java开发环境。

java内存布局

总体:程序计数器,虚拟机栈,本地方法栈,堆,方法区(包含运行时常量池),直接内存。

  • 程序计数器

唯一没有内存逸出的区域,记录程序的分支跳转等信息。占用内存特别小,可忽略不计。当前现成的代码执行行号记录,线程上下文切换就是通过计数器回复现场继续执行的,各线程独立存储,互不影响。只记录java方法的计数,native方法程序计数器为空。

  • 虚拟机栈

虚拟机栈主要包含java方法执行时哥哥方法的栈贞。栈贞里面主要包含局部变量表,操作数栈,动态连接,方法出口等信息。

平时大家说的栈,其实就是局部变量表,java八大基本类型以及引用类型数据都存在这里,局部变量表以slot为单位存储,一个方法局部变量表需要多少个slot在编译期间就能确定咯,循环类的块级结构slot会复用~~~

此外,long和double会占用两个slot,在java并发编程实战中有提到这样会可能导致并发情况下读double和long数据高地位错乱问题,其实本书作者建议知道就行,忘记这回事吧,不会出现的。。。。

栈这个区域,有栈深度,一直递归或者方法调用深度确实太深,会stackoverflowexception, 栈将内存不足,会报ooom异常。传说一般服务器1000-2000的栈深度没啥问题,对了斐波那契数列f(n)=f(n-1)+f(n-2);用最原始的地鬼解,不用map缓存或者改为非递归实现,这栈深度一般扛不住啊、、

-Xss 128k 一个栈的大小

虽然栈定义了两种情况下的异常,但是到底是栈深度太深了导致栈空间不足还是栈的局部变量表太大了导致的也说不清楚,书中作者做了实验,设置栈空间为128k,第一种方法是直接无限递归调用自己,大概可以调用2000次,然后跑stackoverflow异常,然后他在方法里定义大量的局部变量,使得一个栈就非常大,递归调用800次后也报了stackoverflow异常。。。。。。

tips:栈中有可能直接分配对象数据的,即java6之后的栈上分配优化,一些只会在当前线程中使用的变量直接在栈上分配内存,就不需要gc回收了,随着栈帧出栈就全部清除了。

  • 本地方法栈

sun hotpot把本地方法栈和虚拟机栈合在一起的。。。

以前 所有的对象,数组都一定是分配在堆上,栈上只存引用和基本类型。而后面虚拟机的优化技术出现,,栈上分配,标量替换这两个逼玩意儿有可能一些对象不会放在堆里啦。

java的gc主要就是针对这个区域。

堆逸出模拟特别简单,一直创建新对象就好了。。。

jvm调节(-Xmx -Xms)

  • 方法区

这个模块在java8中已经被metaspace替代,一部分数据放到了堆中,类信息等放在metaspace中。

方法区中主要存虚拟机加载的类的信息,及时编辑加载的的类信息等。它还包含运行时常量池。

方法去从jdk1.6到1.7到1.8慢慢被完全取代为metasqpace,在jdk1.7中,字面量和类的静态变量都转移到了堆,符号引用转移到了本地堆,方法区中只有加载的类的基本信息了。到了jdk1.8,字面量和静态变量等信息都全部转移到了java堆中,类的基本信息全部转移到metaspace,方法区被彻底移除。java堆相比之前大了不少。所以以下代码:

public class StringOomMock {
    static String  base = "string";
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        for (int i=0;i< Integer.MAX_VALUE;i++){
            String str = base + base;
            base = str;
            list.add(str.intern()); // 放进常量池
        }
    }
}

在就java6中会报OOM:Pergen Space, java7中会报OOM:java heap space, java8中会报OOM:java heap space

移除方法区的主要原因有:1.方法区经常包内存溢出,放到本地内存中,就只受本地内存大小限制了,相对来说不会那么容易就溢出。2.hotspot虚拟机的方法区是比较特别的,其他的虚拟机一般都没有持久代这一说,为了方便融合,必须去掉方法区。

如果Metaspace的空间占用达到了设定的最大值,那么就会触发GC来收集死亡对象和类的加载器。根据JDK 8的特性,G1和CMS都会很好地收集Metaspace区(一般都伴随着Full GC)。 为了减少垃圾回收的频率及时间,控制吞吐量,对Metaspace进行适当的监控和调优是非常有必要的。

  • 运行时常量池

在java6及之前,属于方法区,之后被划分到了java堆中。

主要存放class文件常量池中的字面量和符号引用。

* class常量池存的是,常量的字面量,符号引用。。。
* 运行时常量池会在类加载之后,对字面量和符号引用进行解析,然后把值存入运行时常量池
* 运行时常量池在运行期间也是可以动态再加入常量的,比如说 String.intern()方法

所以,各个方法中的字符串,类变量里的static final修饰的int,String,float等基本类型也都属于常量。但是数值类常量也没有必要写到常量池中,因为它本身就是一个跟指针一样大小的东西,装入常量池,再用一个指针读出,再写入目标变量,与直接把值写入目标变量相比,消耗大,结果一样,所以没有意义。

看以下代码:

1 String s1 = "Hello";
 2 String s2 = "Hello";
 3 String s3 = "Hel" + "lo";
 4 String s4 = "Hel" + new String("lo");
 5 String s5 = new String("Hello");
 6 String s6 = s5.intern();
 7 String s7 = "H";
 8 String s8 = "ello";
 9 String s9 = s7 + s8;
10           
11 System.out.println(s1 == s2);  // true,在class编译时,s1和s2都是已知的固定字符串,编译器会直接把"Hello"放入class常量池中,运行时将其放入运行时常量池,此时s1和s2都同时指向同一个常量池中的字符串。
12 System.out.println(s1 == s3);  // true, s3将两个已知的固定字符串进行+操作,编译器在编译期间会进行优化直接当做`Hello`处理,所以结果和 s1==s2一样.
13 System.out.println(s1 == s4);  // false, s4中`new String("lo")`这个操作编译器不会进行优化,所以s4的具体指需要等到运行期间动态在堆中生成字符串`lo`后再进行拼接,而运行时形成的字符串如果没有手动`intern`将不会自动进入运行时常量池,所以不会像等
14 System.out.println(s1 == s9);  // false, 这里虽然s7和s8在编译期间其实已经确定了值,但是在做拼接时,因为s7和s8是变量,编译器目前没有如此智能,所以会等到运行时再作拼接,所以不相等。
15 System.out.println(s4 == s5);  // false,不多解释,两个值都是在运行时分配的
16 System.out.println(s1 == s6);  // true,手动intern到常量池,肯定相等。

tips:
运行时常量池中的常量,基本来源于各个class文件中的常量池。
程序运行时,除非手动向常量池中添加常量(比如调用intern方法),否则jvm不会自动添加常量到常量池

  • 直接内存

主要是 nio使用,具体还没有去研究。。。

-XX;MaxDirectoryMemorySize

java对象访问

  • 句柄方式,多一步寻址,指针变了只用改变句柄。
  • 直接指针,快,改变了地址不灵活。目前sunhotpot采用、、、
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容