内存寻址过程 我们知道JVM是内存中的虚拟机,主要使用内存进行存储,所有类、类型、方法,都是在内存中,这决定着我们的程序运行是否健壮、高效。 在Java虚拟机栈中,一个栈帧对应一个方法,,方法执行时会在虚拟机栈中创建一个栈帧,而且当前虚拟机栈只能有一个活跃的栈帧,并且处于栈顶,当前方法结束后,可能会将返回值返回给调用它的方法,而自己将会被弹出栈(即销毁),下一个栈顶将会被执行。 举例说明: ByteCodeSample.java 对其进行编译生成.class文件 然后用javap -verbose 进行反编译 生成如下: 执行add(1,2) 以下是程序在JVM虚拟机栈中的执行过程 执行完之后,当前线程虚拟机栈的栈帧会弹出,对应的其他方法与当前栈帧的连接释放、引用释放,它的下一个栈帧成为栈顶。 我们知道,一个栈帧对应一个方法,存放栈帧的线程虚拟栈是有深度限制的,我们调用递归方法,每递归一次,就会创建一个新的栈帧压入虚拟栈,当超出限度后,就会报此错误。 举例说明: 结果: 解决方法是限制递归次数,或者直接用循环解决。 还有就是,由JVM管理的虚拟机栈数量也是有限的,也就是线程数量也是有限定。 由于栈帧在方法返回后会自动释放,所有栈是不需要GC来回收的。 元空间(MetaSpace)在jdk1.7之前是属于永久代(PermGen)的,两者的作用就是记录class的信息,jdk1.7中,永久代被移入堆中解决了前面版本的永久代分配内存不足时报出的OutOfMemoryError,jdk1.8之后元空间替代了永久代。 我们来看下面这个例子: 说到这里我们不得不提一下String.intern()方法在jdk版本变更中的不同 JDK6:当调用intern方法时,如果字符串常量池先前已创建出该字符串对象,则返回池中的该字符串的引用。否则,将此字符串对象添加到字符串常量池中,并且返回该字符串对象的引用。 JDK6+:当调用intern方法时,如果字符串常量池先前已创建出该字符串对象,则返回池中的该字符串的引用。否则,如果该字符串对象已经存在于Java堆中,则将堆中,则将堆中对此对象的引用添加到字符串常量池中,并且返回该引用;如果堆中不存在,则在池中创建该字符串并返回其引用 我们看一个例子: jdk1.8下运行结果为 分析: jdk1.6下结果: 第一个false跟上边的一样,第二个false是因为jdk1.6的intern()发现常量池中没有”aa”,则直接将此字符串对象添加到常量池中,两个”aa”的地址是不一样的,一个是堆中的一个是常量池中的,故结果也是false。 如有不对,请大家下方评论区指正,谢谢文章目录
一、你了解JVM内存结构吗
在这之前需要知道

地址空间划分
JVM内存结构图——JDK1.8

下面我们会对图中五个部分进行详细说明1.1、程序计数器
在后边的举例中我们可以看到程序计数器的作用。1.2、虚拟机栈(JVM Stack)

package com.mtli.jvm.model; /** * @Description:测试JVM内存模型 * @Author: Mt.Li * @Create: 2020-04-26 17:47 */ public class ByteCodeSample { public static int add(int a , int b) { int c= 0; c = a + b; return c; } } javac com/mtli/jvm/model/ByteCodeSample.java javap -verbose com/mtli/jvm/model/ByteCodeSample.class Classfile /E:/JavaTest/javabasic/java_basic/src/com/mtli/jvm/model/ ByteCodeSample.class Last modified 2020-4-26; size 289 bytes MD5 checksum 2421660bb241239f1a67171bb771521f Compiled from "ByteCodeSample.java" public class com.mtli.jvm.model.ByteCodeSample minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER // 描述类信息 Constant pool: #1 = Methodref #3.#12 // java/lang/Object."<ini t>":()V #2 = Class #13 // com/mtli/jvm/model/Byt eCodeSample #3 = Class #14 // java/lang/Object #4 = Utf8 <init> #5 = Utf8 ()V #6 = Utf8 Code #7 = Utf8 LineNumberTable #8 = Utf8 add #9 = Utf8 (II)I #10 = Utf8 SourceFile #11 = Utf8 ByteCodeSample.java #12 = NameAndType #4:#5 // "<init>":()V #13 = Utf8 com/mtli/jvm/model/ByteCodeSample #14 = Utf8 java/lang/Object // 以上是常量池(线程共享) { public com.mtli.jvm.model.ByteCodeSample(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/O bject."<init>":()V 4: return LineNumberTable: line 8: 0 // 以上是初始化过程 public static int add(int, int); descriptor: (II)I // 接收两个int类型变量 flags: ACC_PUBLIC, ACC_STATIC // 描述方法权限和类型 Code: stack=2, locals=3, args_size=2 // 操作数栈深度 、 容量 、参数数量 0: iconst_0 1: istore_2 2: iload_0 3: iload_1 4: iadd 5: istore_2 6: iload_2 7: ireturn LineNumberTable: line 10: 0 // 这里的第0行对应我们代码中的第10行 line 12: 2 line 13: 6 } SourceFile: "ByteCodeSample.java" 
图不是很清楚,我来说一下过程,最下边的是程序计数器(前边提到的),最上边是操作指令,中间是局部变量表和操作数栈(位置从0开始)
1.1.1、java.lang.StackOverflowError问题
package com.mtli.jvm.model; /** * @Description:斐波那契 * F(0)=0,F(1)=1,当n>=2的时候,F(n) = F(n-1) + F(n-2), * F(2) = F(1) + F(0) = 1,F(3) = F(2) + F(1) = 1+1 = 2 * 0, 1, 1, 2, 3, 5, 8, 13, 21, 34... * @Author: Mt.Li * @Create: 2020-04-26 18:33 */ public class Fibonacci { public static int fibonacci(int n) { if(n>=0){ if(n == 0) {return 0;} if(n == 1) {return 1;} return fibonacci(n-1) +fibonacci(n-2); } return n; } public static void main(String[] args) { System.out.println(fibonacci(0)); System.out.println(fibonacci(1)); System.out.println(fibonacci(2)); System.out.println(fibonacci(3)); System.out.println(fibonacci(1000000)); // java.lang.StackOverflowError } } 
1.3、本地方法栈
1.4、元空间(MetaSpace)
1.4.1、MetaSpace相比PermGen的优势
1.5、Java堆(Heap)
二、JVM三大性能调优参数 -Xms -Xmx -Xss的含义
三、Java内存中堆和栈的区别——内存分配策略
需要先了解
区别

四、元空间、堆、线程独占部分间的联系——内存角度

以下是各个部分包含的内容:

五、不同JDK版本之间的intern()方法的区别——JDK6 VS JDK6+
String s = new String("a"); s.intern(); public class InternDifference { public static void main(String[] args) { String s = new String("a"); s.intern(); String s2 = "a"; System.out.println(s == s2); String s3 = new String("a") + new String("a"); s3.intern(); String s4 = "aa"; System.out.println(s3 == s4); } } false true
false false
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算
官方软件产品操作指南 (170)