Java程序内存分配问题 想进入黑马最近在看毕向东老师的java视频,之前看过马士兵老师的java视频,讲的也不错但没有毕老师讲的通俗易懂。 两个老师在讲内存分配时有些不一致,具体是静态变量的内存分配。 下面是我对java程序在内存中分配过程的简介。可能有不对的地方,希望大家指出错误,给出正确的解释。 先介绍5张图,图1是UNIX环境高级编程(第二版)第七章 第7.6节截图 file:///C:/Users/lee/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg 图1 C程序的存储空间布局 正文:CPU执行的机器指令部分 初始化的数据:通常称为数据段,包含了程序中明确赋值的变量 未初始化的数据:通常称为bss段(blockstarted by symbol:符号开始块)在程序执行前,内核将此段中的数据初始化为0或空指针。
栈:自动变量以及每次函数调用时所需保存的信息都存放在此段 堆:通常在堆中进行动态分配存储空间。 图2是操作系统概念(第九版)第二部分第三章进程截图。 file:///C:/Users/lee/AppData/Local/Temp/msohtmlclip1/01/clip_image004.jpg 图2 内存中的进程 Code:文本段 程序代码。 Data:数据段 全局变量 。 Heap:堆区 程序运行期间动态的分配内存。 Stack:栈区 临时数据
图3是马士兵老师的java视频截图 file:///C:/Users/lee/AppData/Local/Temp/msohtmlclip1/01/clip_image006.jpg 图3 马士兵java 内存分配图 马老师的观点是: Codesegment:代码区存放代码 Datasegment:数据区存放静态变量和字符串常量 Stack:栈区 存放局部变量 Heap:堆区 存放new出来的东西。 图4 是根据毕老师 java 视频讲解画出的内存分配图 。 file:///C:/Users/lee/AppData/Local/Temp/msohtmlclip1/01/clip_image008.jpg 图4 毕老师java内存分配图 图5是本人根据图2结合图3改变而来的。 file:///C:/Users/lee/AppData/Local/Temp/msohtmlclip1/01/clip_image010.jpg 图5 改动后的内存分配图 本文以图5为主讲述java程序在内存中的分配 1 代码区:加载要执行的程序代码 2 数据区:存放程序中用static关键字修饰的静态变量和字符串常量 3 堆区:new出来的东西 4 栈区:保存临时数据和函数入栈时所需保存的信息 以TestPerson.java为例讲解内存具体分配情况 TestPerson.java class Person { Stringname ; private static String city = "中国"; intage ; publicPerson(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()) ; } }
file:///C:/Users/lee/AppData/Local/Temp/msohtmlclip1/01/clip_image012.jpg 图6 函数加载过程 1先加载主函数main( ),将其调用信息入栈,序号1。 2定义一个对象引用变量p1(栈中分配),序号2。 3在new出对象前先加载对应构造函数Person(String name, int age),将其调用信息入栈,序号3。 4执行Person构造函数时,先调用超类Object默认的无参构造函数Object( ),将其调用信息入栈,序号4。 5构造函数Object()执行完毕后,它的栈空间被弹出,接着继续执行构造函数Person自己的函数体,如图7。 6在new对象时,随着类的加载,静态变量 city 优先在数据块中分配存储空间。如图7序号5。 7在new对象时,将字符串实参"张三"分配到数据区(图7序号6所示),并赋值给构造函数Person的形参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出的对象,如图8所示。接着继续执行主函数中的System.out.println()函数。如图9所示 file:///C:/Users/lee/AppData/Local/Temp/msohtmlclip1/01/clip_image014.jpg 图7对象new出对象的过程 file:///C:/Users/lee/AppData/Local/Temp/msohtmlclip1/01/clip_image016.jpg 图8 对象 new出后的情况 10执行System.out.println(p1.talk())函数时把println()函数入栈(图9中绿色虚线框),println调用了对象p1的talk( )函数,所以把talk( )加载到栈顶,如图9中红色虚线框所示。 file:///C:/Users/lee/AppData/Local/Temp/msohtmlclip1/01/clip_image018.jpg 图9 11当talk( )函数执行完毕后,它的栈块被弹出,接着执行println( )函数,如图10所示。 12当println( )函数执行完毕后,它的栈块被弹出,接着执行main()函数,如图10所示 13此时main函数也执行完毕,它的栈块被弹出。引用变量p1消失,如图10所示。 14整个程序执行完毕后,由java虚拟机的垃圾回收站负责回收堆中的空间。 15栈中的空间是自动释放。 16数据区中的静态变量city和字符串常量“张三”不知道由谁释放??? file:///C:/Users/lee/AppData/Local/Temp/msohtmlclip1/01/clip_image020.jpg 图10
通过看两位老师的视频和参考HeadFist Java等书籍,对java程序在内存中的分配做出了自己的理解,总感觉某些地方理解的有误,甚至有些地方的描述可能有点牵强附会,请大家给予宝贵的指导,本人万分感谢。
|