黑马程序员技术交流社区
标题: Java程序内存分配问题 [打印本页]
作者: lee123 时间: 2015-1-14 17:28
标题: Java程序内存分配问题
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程序在内存中的分配做出了自己的理解,总感觉某些地方理解的有误,甚至有些地方的描述可能有点牵强附会,请大家给予宝贵的指导,本人万分感谢。
-
1图1 C程序的存储空间布局.jpg
(32.54 KB, 下载次数: 9)
-
2图2内存中的进程.jpg
(29.9 KB, 下载次数: 7)
-
3图3马士兵java 视频内存分配图.jpg
(116.8 KB, 下载次数: 10)
-
4图4根据毕老师java视频讲解画出的内存分配图.jpg
(14.67 KB, 下载次数: 9)
-
5图5 改动后的内存分配图.jpg
(45.13 KB, 下载次数: 11)
-
6图6 函数加载过程.jpg
(32.29 KB, 下载次数: 11)
-
7图7对象new出对象的过程.jpg
(61.38 KB, 下载次数: 7)
-
8图8 对象 new出后的情况.jpg
(43.18 KB, 下载次数: 9)
-
9图9 函数出栈过程.jpg
(50.14 KB, 下载次数: 6)
-
10图10程序执行结束.jpg
(68.19 KB, 下载次数: 11)
作者: lee123 时间: 2015-1-15 21:19
谢谢鼓励,由于原文不能显示图片,我把图片放在当附件上传上去了,附件图片顺序就是原文中的顺序。自己在做总结时,感觉某些地方描述的不太恰当或者表达的有误,所以请大家指出错误,共同进步
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |