欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JVM 内存初学 (堆(heap)、栈(stack)和方法区(method) )(转载)

程序员文章站 2022-04-08 19:05:18
想想面试的时候很多会问jvm这方面的问题虽然还是菜鸟不太能用到现在但是还是了解一下, 找资料的时候看见个大佬写的很好转载到这方便以后自己复习和给大佬做宣传 以下为大佬的博客原文: 这两天看了一下深入浅出JVM这本书,推荐给高级的java程序员去看,对你了解JAVA的底层和运行机制有比较大的帮助。废话 ......

 想想面试的时候很多会问jvm这方面的问题虽然还是菜鸟不太能用到现在但是还是了解一下,

找资料的时候看见个大佬写的很好转载到这方便以后自己复习和给大佬做宣传

 

以下为大佬的博客原文:

这两天看了一下深入浅出jvm这本书,推荐给高级的java程序员去看,对你了解java的底层和运行机制有
比较大的帮助。
废话不想讲了.入主题:
先了解具体的概念:
java的jvm的内存可分为3个区:堆(heap)、栈(stack)和方法区(method)

堆区:
1.存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令)
2.jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身
栈区:
1.每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中
2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。
方法区:
1.又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。
2.方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。
为了更清楚地搞明白发生在运行时数据区里的黑幕,我们来准备2个小道具(2个非常简单的小程序)。
appmain.java

 public   class  appmain                

//运行时, jvm 把appmain的信息都放入方法区

{

public   static   void  main(string[] args)  //main 方法本身放入方法区。

{

sample test1 = new  sample( " 测试1 " );   //test1是引用,所以放到栈区里, sample是自定义对象应该放到堆里面

sample test2 = new  sample( " 测试2 " );

test1.printname();

test2.printname();

}


sample.java

 public   class  sample        //运行时, jvm 把appmain的信息都放入方法区

{

/** 范例名称 */

private  name;      //new sample实例后, name 引用放入栈区里,  name 对象放入堆里

/** 构造方法 */

public  sample(string name)

{

this .name = name;

}

/** 输出 */

public   void  printname()   //print方法本身放入 方法区里。

{

system.out.println(name);

}


ok,让我们开始行动吧,出发指令就是:“java appmain”,包包里带好我们的行动向导图,let’s go!
JVM 内存初学 (堆(heap)、栈(stack)和方法区(method) )(转载)
系统收到了我们发出的指令,启动了一个java虚拟机进程,这个进程首先从classpath中找到appmain.class文件,读取这个文件中的二进制数据,然后把appmain类的类信息存放到运行时数据区的方法区中。这一过程称为appmain类的加载过程。
接着,java虚拟机定位到方法区中appmain类的main()方法的字节码,开始执行它的指令。这个main()方法的第一条语句就是:
sample test1=new sample("测试1");
语句很简单啦,就是让java虚拟机创建一个sample实例,并且呢,使引用变量test1引用这个实例。貌似小case一桩哦,就让我们来跟踪一下java虚拟机,看看它究竟是怎么来执行这个任务的:
1、 java虚拟机一看,不就是建立一个sample实例吗,简单,于是就直奔方法区而去,先找到sample类的类型信息再说。结果呢,嘿嘿,没找到@@,这会儿的方法区里还没有sample类呢。可java虚拟机也不是一根筋的笨蛋,于是,它发扬“自己动手,丰衣足食”的作风,立马加载了sample类,把sample类的类型信息存放在方法区里。
2、 好啦,资料找到了,下面就开始干活啦。java虚拟机做的第一件事情就是在堆区中为一个新的sample实例分配内存, 这个sample实例持有着指向方法区的sample类的类型信息的引用。这里所说的引用,实际上指的是sample类的类型信息在方法区中的内存地址,其实,就是有点类似于c语言里的指针啦~~,而这个地址呢,就存放了在sample实例的数据区里。
3、 在java虚拟机进程中,每个线程都会拥有一个方法调用栈,用来跟踪线程运行中一系列的方法调用过程,栈中的每一个元素就被称为栈帧,每当线程调用一个方法的时候就会向方法栈压入一个新帧。这里的帧用来存储方法的参数、局部变量和运算过程中的临时数据。ok,原理讲完了,就让我们来继续我们的跟踪行动!位于“=”前的test1是一个在main()方法中定义的变量,可见,它是一个局部变量,因此,它被会添加到了执行main()方法的主线程的java方法调用栈中。而“=”将把这个test1变量指向堆区中的sample实例,也就是说,它持有指向sample实例的引用。
ok,到这里为止呢,java虚拟机就完成了这个简单语句的执行任务。参考我们的行动向导图,我们终于初步摸清了java虚拟机的一点点底细了,cool!
接下来,java虚拟机将继续执行后续指令,在堆区里继续创建另一个sample实例,然后依次执行它们的printname()方法。当java虚拟机执行test1.printname()方法时,java虚拟机根据局部变量test1持有的引用,定位到堆区中的sample实例,再根据sample实例持有的引用,定位到方法去中sample类的类型信息,从而获得printname()方法的字节码,接着执行printname()方法包含的指令。

 

 

转载至:https://www.cnblogs.com/dingyingsi/p/3760730.html

作者:

 

2019-03-07  19:58:34