Java学习笔记之程序内存分配问题

来源:互联网 发布:淘宝小号淘气值查看 编辑:程序博客网 时间:2024/06/05 09:10

Java程序内存分配问题

通过学习毕向东、马士兵老师的视频对java程序的内存分配的理解。

先介绍5张图片

图1是UNIX环境高级编程(第二版)的第七章 进程环境,第7.6节 C程序的存储空间布局。

111111111

图1 C程序的存储空间布局

书中文字说明

正文:CPU执行的机器指令部分

初始化的数据:通常称为数据段,包含了程序中明确赋值的变量,例如,C程序中任何函数之外的声明:int  max = 99;

未初始化的数据:通常称为bss段(blockstarted by symbol:符号开始块)在程序执行前,内核将此段中的数据初始化为0或空指针。例如,函数外的声明:

long  sum [ ] = 1000.

栈:自动变量以及临时变量都存放在此段

堆:通常在堆中进行动态分配存储空间。

图2是操作系统概念(第九版)的第二部分进程管理 第三章 进程 截图。

2222222

图2 内存中的进程

书中文字说明

Code:文本段 程序代码。

Data:数据段 全局变量 。 (注意:java中没有全局变量这一说法。)

Heap:堆区 程序运行期间动态的分配内存。

Stack:栈区 临时数据(例如函数参数、返回地址和局部变量)。

图3是马士兵老师的java视频截图

3333333333

图3 马士兵java 视频内存分配图

马老师的观点是:

         Codesegment:代码区存放代码

         Datasegment:数据区存放静态变量和字符串常量

         Stack:栈区 存放局部变量

         Heap:堆区 存放new出来的东西。

图4是毕老师在讲“074_面向对象(Static关键字)”时,讲到方法区也称为共享区或者数据区,毕老师把code区和data区放在一起了,如图4所示。

444444444444

图4 根据毕老师java视频讲解画出的内存分配图

图5是本人根据图2结合图3改变而来的。

555555555

图5 改动后的内存分配图

本文以图5为主讲述java程序在内存中的分配

1、  代码区:加载要执行的程序代码

2、  数据区:存放程序中用static关键字修饰的静态变量和字符串常量

3、  堆区:new出来的东西,包括有名对象和匿名对象,类的成员变量(实例变量)

4、  栈区:保存临时数据,如局部变量,函数参数,函数返回值,函数入栈时所需保存的信息

以TestPerson.java为例讲解内存具体分配情况

TestPerson.javaclass Person {        String name ;        private static String city = "中国";        int age ;        public Person(String name,int age)   {//super(); == Object();                this.name = name ;                 this.age = age ;        }        public String talk()   {return "我是:"+this.name+",今年: "+this.age+"岁,来自: "+city;        }}public class TestPerson {publicstatic void main(String[] args)  {Person p1 = new Person("张三",22);System.out.println(p1.talk()) ;}}

TestPerson.java内存分配图

66666666

图6 函数加载过程

程序TestPerson.java执行过程说明

1、把code区的主函数main( )入栈,图6序号1所示。

2、定义一个对象引用变量p1(栈中分配),图6序号2所示。

3、在new出对象前先将该类对应构造函数Person(String name, int age)入栈,图6序号3所示。

4、执行Person(Stringname, int age)构造函数时,先调用超类Object的默认无参构造函数Object( ),将其入栈,图6序号4所示。

5、超类构造函数Object()执行完毕后,它的栈空间被弹出,接着继续执行Person类的构造函数Person(String name, int age)自己的函数体,如图7所示。

6、  在new对象时,随着类的加载,静态变量 city 优先在数据块中分配存储空间。如图7序号5所示。

7、  在new对象时,将字符串实参"张三"分配到数据区(图7序号6所示),并赋值给构造函数Person(Stringname, int age)的形参neme(栈中分配空间),

即name = "张三"如图中黄色虚线。而形参name 又赋值给类Person的成员变量name,即this.name = name如图7中红色虚线,所以成员变量name也指向数

据区的"张三",即this.name= "张三"如图7中红色实线。

8、  将实参变量22赋值给构造函数的形参age(栈中分配空间),即age= 22,如图7中红色方框所示,形参age又赋值给类Person的成员变量age,

即this.age = age =22,如图中绿色虚线所示。

9、  构造函数执行完毕后,它的函数体内的临时变量消失,函数栈空间被弹出,只剩下引用变量P1指向堆中new出的对象,(即P1保存该对象的在堆空间的地

址),如图8所示。接着继续执行主函数中的System.out.println()函数。如图9所示

777777777

图7对象new出对象的过程

88888888888888

图8 对象 new出后的情况

10、执行主函数中System.out.println(p1.talk())函数,先把println()函数入栈(图9中绿色虚线框),又因为println调用了对象p1的talk( )函数,所以把talk( )加载到

栈顶,如图9中红色虚线框所示。

9999999999

图9 函数出栈过程

11、当talk( )函数执行完毕后,它的栈块被弹出,对象消失。p1不再指向堆空间中new出的对象,接着执行println( )函数,如图10所示。

12、当println( )函数执行完毕后,它的栈块被弹出,接着执行main()函数,如图10所示

13、此时main函数也执行完毕,它的栈块被弹出。引用变量p1消失,如图10所示。

14、整个程序执行完毕后,由java虚拟机的垃圾回收站负责回收堆中的空间。

15、栈中的空间是自动释放的,当栈中临时变量的生命周期结束或函数调用结束函数出栈时,相应的栈空间就自动释放了。

16、疑问:数据区的静态变量city和字符串常量“张三”不知道由谁释放,难道也是java虚拟机的垃圾回收机制负责回收吗??

1000000000000

图10程序执行结束

通过学习两位老师的视频和查看相关书籍,对java程序在内存中的分配做出了自己的理解,总感觉某些地方理解的有误,甚至有些地方的描述可能有点牵强附会,请大家批评指正,谢谢。

1 0
原创粉丝点击