新手求教JAVA中内存相关问题

AC_majia 2014-09-23 02:37:08
各位前辈好,我是一个初学java的新手,最近学习内存部分内容遇到了如下问题,还望各位赐教。

1.是否所有基本类型数据都存储在栈上,那假如有这样一段语句  Point p1 = new Point(1, 1);
传给其构造函数的1,1是int型,为什么他们存储在堆里。
 
2.在程序编译的时候,开始时是否只编译我运行的这个,有主函数的这个类,而其他的类(例如Point类)是不是不会被编译,在具体运行到该语句的时候再编译该类?
 
3.一个对象被创建时,会有额外的堆的开支来存储与这个对象的相关信息(比如方法之类的?)。我在网上看别人的文章时,有看到过“相同类实例化的对象只开辟一块空间来存储这些信息,而不是每个对象被创建时都会有这些额外开支”(我不确定是不是这样说,难道是说 被编译时每个类都会有独立的开支,而对象被创建时又会有另外的独立开支?)
 
4.如果我创建一个函数,这个函数需要被不断、大量重用,那么我是否应该尽力使传到该函数的参数为值类型(最好是byte、boolean),传递对象比传递值类型(如int)更占用内存么?  因为我最近看视频才知道,传递一个对象的话,只是传递引用,那么不管传递多大的对象,传递的引用其大小不都是一样么,而且不用额外开辟储存空间存储这个引用,这样来说穿引用不是比传值类型更占优势?
 
5.程序在编译时,类里面的静态成员,常量就会被放到   静态、常量区,假如我在某个方法中有这样一段语句。Point p1 = new Point(1, 1);   而我写的Point类中也有自己的静态与常量成员,那这些静态成员、常量也是被分配到静态、常量区存储么?是在程序一开始编译的时候存储,还是在创建第一个该对象时临时加进去?
 
6.对于ArrayList,它好像是顺序表,是否意味着它在堆上的存储是连续的?那当它自己初始化的容量不足,需要扩容时,他需要重新在堆开辟空间存储新元素,那么是否有可能ArrayList在堆上就不连续了,而是一块一块的分布,那这样不就与顺序表的概念相冲突了么?
...全文
232 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
gaofuqi 2014-09-25
  • 打赏
  • 举报
回复
1.是否所有基本类型数据都存储在栈上,那假如有这样一段语句 Point p1 = new Point(1, 1); 传给其构造函数的1,1是int型,为什么他们存储在堆里。 =========================================================================== 是否所有基本类型数据都存储在栈上:否; p1是内存地址,如果 p1是成员变量保存在堆里,如果是局部变量,会保存在Java虚拟机栈的局部变量表; 2.在程序编译的时候,开始时是否只编译我运行的这个,有主函数的这个类,而其他的类(例如Point类)是不是不会被编译,在具体运行到该语句的时候再编译该类? =============================================================================================== Java不是脚本语言,不会动态编译,但可以动态加载; 3.一个对象被创建时,会有额外的堆的开支来存储与这个对象的相关信息(比如方法之类的?)。我在网上看别人的文章时,有看到过“相同类实例化的对象只开辟一块空间来存储这些信息,而不是每个对象被创建时都会有这些额外开支”(我不确定是不是这样说,难道是说 被编译时每个类都会有独立的开支,而对象被创建时又会有另外的独立开支?) ================================================================================== 这个要从Java虚拟机的运行时数据区说起,主要有方法区、堆、Java虚拟机栈、本地方法栈、程序计数器; 方法区: 会保存已Java虚拟机加的类信息、常量、静态变量、即时编译后的代码; 堆 : 存放对象实例和数组; Java虚拟机栈:保存局部变量表、操作数栈、方法出口等; 本地方法栈: Java虚拟机栈类似,只不过Java虚拟机栈是Java虚拟机调用Java方法,本地方法栈是Java虚拟机 调用本地方法服务; 你说的“只开辟一块空间来存储这些信息”,这个应该属于类信息,会保存在方法区中; “难道是说 被编译时每个类都会有独立的开支,而对象被创建时又会有另外的独立开支”这样理解是正确的, 因为类信息保存在方法区,而对象实例则Java堆中。 4.如果我创建一个函数,这个函数需要被不断、大量重用,那么我是否应该尽力使传到该函数的参数为值类型(最好是byte、boolean),传递对象比传递值类型(如int)更占用内存么? 因为我最近看视频才知道,传递一个对象的话,只是传递引用,那么不管传递多大的对象,传递的引用其大小不都是一样么,而且不用额外开辟储存空间存储这个引用,这样来说穿引用不是比传值类型更占优势? =============================================================================================== 在Java基本类型都是传值,引用类型都传内存地址。传什么其实没什么区别,内存地址的范围应该int大吧。“而且不用额外开辟储存空间存储这个引用”这个很明显不可能。 5.程序在编译时,类里面的静态成员,常量就会被放到 静态、常量区,假如我在某个方法中有这样一段语句。Point p1 = new Point(1, 1); 而我写的Point类中也有自己的静态与常量成员,那这些静态成员、常量也是被分配到静态、常量区存储么?是在程序一开始编译的时候存储,还是在创建第一个该对象时临时加进去? =============================================================================================== 静态成员、常量在方法区,在类加载时加入方法区; 6.对于ArrayList,它好像是顺序表,是否意味着它在堆上的存储是连续的?那当它自己初始化的容量不足,需要扩容时,他需要重新在堆开辟空间存储新元素,那么是否有可能ArrayList在堆上就不连续了,而是一块一块的分布,那这样不就与顺序表的概念相冲突了么? ============================================================================================ ArrayList就是数组,所谓的扩容,其实就是重新分配一块更大的内存空间,再将以前的元素复制到新的内存空间,还是顺序表,没什么冲突 其实上面的问题都能在《深入Java虚拟机》中找到,而且书中描述得更详细和系统,楼主可以了解一下。
AC_majia 2014-09-25
  • 打赏
  • 举报
回复
自顶,求继续解答啊~!
windsunmoon 2014-09-23
  • 打赏
  • 举报
回复
楼主是个好孩子。 我回答 第二题:编译的时候,会先编译所依赖的那些类B,如果B也依赖其他类,那么先编译B依赖的类,依次递归。
AC_majia 2014-09-23
  • 打赏
  • 举报
回复
引用 1 楼 zhuxiaoleiwoaini 的回复:
1, 定义:在函数中定义的基本类型变量和对象的引用变量都在函数的栈内存中分配; 堆内存用来存放由new创建的对象和数组以及对象的实例变量; 解释: 用Point p1 ;声明一个对象p1 时,将在栈内存为对象的引用变量p1 分配内存空间,但Point 的值为空,称p1是一个空对象。空对象不能使用,因为它还没有引用任何”实体”。 对象实例化时的内存模型,当执行p1=new Point(1, 1);时,会做两件事:在堆内存中为类的成员变量1,1初始化分配内存,最后调用构造方法,为成员变量赋值。返回堆内存中对象的引用(相当于首地址)给引用变量p1,以后就可以通过p1来引用堆内存中的对象了。
你好,层主,谢谢你的回复,第一个问题我已经懂了。 假如有这样一段代码: Point p1 = new Point(1, 1); Point p2 = new Point(2, 2); Line ln1 = new Line(p1, p2); Line 类是这样的, { public Line(Point p1, Point p2) { startPoint = p1; endPoint = p2; } private Point startPoint; private Point endPoint; } 可以看到这个line类有两个成员变量startPoint和endPoint,我看的那个教学视频中,在创建这个line对象时,首先会为这两个成员变量在堆中初始化相应空间,然后再启动栈帧,为堆中的这两个成员变量赋值。 但是视频中为startPoint和endPoint在堆中开辟的内存空间为4个字节(用来存储p1,p2的地址)。为啥程序会知道要在堆中开辟4个字节,仿佛他就知道我会把startpoint和endpoint指向两个在堆中已经存在的point对象,难道不应该直接开辟与Point对象大小相对应的堆的空间么?因为在初始化startPoint和endPoint的时候我还没有运行构造函数。万一我在构造函数中采取的策略不是使 startPoint = p1; 而是直接 startPoint = new Point(1,1)怎么办? 那这样4个字节的地方不就不够用了?
zhuxiaoleiwoaini 2014-09-23
  • 打赏
  • 举报
回复
1, 定义:在函数中定义的基本类型变量和对象的引用变量都在函数的栈内存中分配; 堆内存用来存放由new创建的对象和数组以及对象的实例变量; 解释: 用Point p1 ;声明一个对象p1 时,将在栈内存为对象的引用变量p1 分配内存空间,但Point 的值为空,称p1是一个空对象。空对象不能使用,因为它还没有引用任何”实体”。 对象实例化时的内存模型,当执行p1=new Point(1, 1);时,会做两件事:在堆内存中为类的成员变量1,1初始化分配内存,最后调用构造方法,为成员变量赋值。返回堆内存中对象的引用(相当于首地址)给引用变量p1,以后就可以通过p1来引用堆内存中的对象了。

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧