Java运行内存分配详解

一. 进程 线程概念

进程:在系统中能独立运行并且作为资源分配的基本单位,它由一组机器指令、数据和栈堆等组成的。简单来讲就是每个应用都是一个进程。

线程:用来执行具体的功能及任务的,需要进程作为载体,是进程的一个实体(进程内部包含一个或多个线程)。线程基本不具有系统资源,但其可以与其他线程共享进程所拥有的资源。

二.堆 栈 方法区概念及关系

每一个运行的Java程序会产生一个进程和一个JVM实例,而每个线程会产生一个或多个线程。每一个JVM实例内部包含一个堆,堆内存放的是创建的类的实例及数组,栈内存放的是对堆中对象的引用。局部变量new出来时会在堆和栈中给其分别分配内存空间,当局部变量声明周期结束之后,栈空间会被立刻回收,而堆则需要等待GC回收。
JVM内存包含3个区:堆、栈、方法区

1.存储的全是对象,每个对象都包含一个与之对应的class信息
2.JVM内只有一个堆区,且被所有线程共享,堆中不存放基本类型和对象的引用,只存放对象及数组本身。

1.每个线程包含一个栈区,内部存放基本数据类型及对对象的引用
2.每个栈内的数据都是私有的,外部不能访问
3.栈分为基本类型变量区、执行文上下环境、操作指令区
方法区(静态区)
1.被所有线程共享,包含所有的class和static变量
2.其包含在整个程序过程当中永远唯一的元素,如class,static变量

三.实例

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();
}
}

public class Sample //运行时, jvm 把appmain的信息都放入方法区
{
/** 范例名称 */
private String name; //new Sample实例后, name 引用放入栈区里, name 对应的 String 对象放入堆里

/** 构造方法 */
public Sample(String name)
{
this .name = name;
}

/** 输出 */
public void printName() //在没有对象的时候,print方法跟随sample类被放入方法区里。
{
System.out.println(name);
}
}
https://www.jb51.net/article/88963.htm
程序运行时,首先启动java虚拟机,然后该进程会从找到AppMain.class文件,然后读取该文件的二进制数据,然后将该信息放到方法区内部。
java虚拟机定位到main()方法开始执行指令。
Sample test1=new Sample(“测试1”);
语句执行过程:

1、 Java虚拟机到方法区找到Sample类的类型信息,没有找到,因为Sample类还没有加载到方法区(这里可以看出,java中的内部类是单独存在的,而且刚开始的时候不会跟随包含类一起被加载,等到要用的时候才被加载)。Java虚拟机立马加载Sample类,把Sample类的类型信息存放在方法区里。
2、 Java虚拟机首先在堆区中为一个新的Sample实例分配内存, 并在Sample实例的内存中存放一个方法区中存放Sample类的类型信息的内存地址。
3、 JVM的进程中,每个线程都会拥有一个方法调用栈,用来跟踪线程运行中一系列的方法调用过程,栈中的每一个元素就被称为栈帧,每当线程调用一个方法的时候就会向方法栈压入一个新帧。这里的帧用来存储方法的参数、局部变量和运算过程中的临时数据。
4、位于“=”前的Test1是一个在main()方法中定义的一个变量(一个Sample对象的引用),因此,它被会添加到了执行main()方法的主线程的JAVA方法调用栈中。而“=”将把这个test1变量指向堆区中的Sample实例。
5、JVM在堆区里继续创建另一个Sample实例,并在main方法的方法调用栈中添加一个Test2变量,该变量指向堆区中刚才创建的Sample新实例。
6、JVM依次执行它们的printName()方法。当JAVA虚拟机执行test1.printName()方法时,JAVA虚拟机根据局部变量test1持有的引用,定位到堆区中的Sample实例,再根据Sample实例持有的引用,定位到方法去中Sample类的类型信息,从而获得printName()方法的字节码,接着执行printName()方法包含的指令,开始执行。

具体详解可参考:https://www.jb51.net/article/88963.htm

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值