解决方案 »
- 如何判别线程池里的任务全部已经完成?
- struts2 iterator标签的的一个问题
- 关于网页形成照片的问题!
- Java Service Wrapper 如何设置java应用程序的运行参数
- 请教Spring整合Hibernate的注入顺序的两个问题?
- JAVA初学者的问题
- 安装了JasperIntelligence,还不能正常使用
- 我要帮助,没学过,老师就叫我们用J2EE做题。求高手们帮忙顶一下!
- 网上到处都是Jbuilder+weblogic的实例无数!为何不见+websphere的!
- myeclipse新建maven项目报错 大牛指点一下啊
- java 实现文件上传到另一台服务器
- 据说会此算法的人 才真正是大牛
对象在堆里,基础变量在栈里另外,a实例中的字符串成员变量s是被分配在内存的哪个区域?常量区还是堆区?
这个字符串是预赋值的,相当于常量,在常量池,也就是方法区里
2、当执行a.f2()语句时,字符串s2的值"bcd"是被分配在堆区,还是常量池?
但凡你在代码里看到的="string"这种类型的东西,全部都在常量池里
1.对象头,主要是对象自己运行时数据(包括hashCode、gc分代年龄、线程持有的锁、锁状态标识等等)和对象的类型;
2.实例数据,是对象真正有效数据;
3.对齐填充,用于占位符;
===============================================================================================1、主函数中,当执行A a=new A()时,我们知道,a相当于指针,被分配在栈中;new A()才是真正的对象,
被分配在堆中。那么,a实例中的引用类型成员变量a和b此时如何分配内存的,分配在哪?指针和实例都在堆中吗?
另外,a实例中的字符串成员变量s是被分配在内存的哪个区域?常量区还是堆区?答:
1.a实例中怎么会出现名称相同的字段(a和b)?
2.a实例的a和b.无是基本类型还是引用类型都在堆中,只是他们指向的值或对象可能是堆中也可能在常量池中;
3.成员变量s也是在堆,s指向的常量池中的常量"bcd"的地址
=============================================================
2、当执行a.f2()语句时,字符串s2的值"bcd"是被分配在堆区,还是常量池?
答:"bcd"是在常量池中,而s2是在栈中;
(1)在函数中定义的基本类型变量和对象的引用变量都在函数的栈内存中分配;
(2)堆内存用来存放由new创建的对象和数组以及对象的实例变量。
经过我自己的研究,“bcd”应该是被分配在了常量池中,不再分配到堆中。
经过我自己的研究,“bcd”应该是被分配在了常量池中,不再分配到堆中。恩恩,你自己有理解就好,不一定我的就是对的,我只是说说我的理解
兄弟,你确定当执行new A()时,a实例中的类型成员变量a和b是在栈中被分配的?你要注意,a和b不是在main函数中直接声明的,而是类的成员变量啊……
其实,我可以把意思说的更明白些:
如果类与类之间出现了组合关系时,当调用类被实例化时,被引用类的指针或者说引用符号,到底是在栈中还是堆中分配的?注意:被引用的类,并非是直接在函数中定义的局部变量。特请注意!!!!
兄弟,我的疑问跟上面的回答一样。我知道字符串s的值是被分配在常量池中,请你看清楚,我是问的,s这个符号引用(从c++的角度看就是指针)本身是被分配在了哪里?堆还是栈?
兄弟,你确定当执行new A()时,a实例中的类型成员变量a和b是在栈中被分配的?你要注意,a和b不是在main函数中直接声明的,而是类的成员变量啊……
其实,我可以把意思说的更明白些:
如果类与类之间出现了组合关系时,当调用类被实例化时,被引用类的指针或者说引用符号,到底是在栈中还是堆中分配的?注意:被引用的类,并非是直接在函数中定义的局部变量。特请注意!!!!
sorry,没看清-_-#,.成员变量全在堆里没错,这个我的说法有问题。方法体里的变量指针在栈里,只出现在方法运行时
兄弟,你确定当执行new A()时,a实例中的类型成员变量a和b是在栈中被分配的?你要注意,a和b不是在main函数中直接声明的,而是类的成员变量啊……
其实,我可以把意思说的更明白些:
如果类与类之间出现了组合关系时,当调用类被实例化时,被引用类的指针或者说引用符号,到底是在栈中还是堆中分配的?注意:被引用的类,并非是直接在函数中定义的局部变量。特请注意!!!!
sorry,没看清-_-#,.成员变量全在堆里没错,这个我的说法有问题。方法体里的变量指针在栈里,只出现在方法运行时也就是说,new A()时,里面的类型成员变量a和b的引用和对象都被分配在堆里了?
兄弟,你确定当执行new A()时,a实例中的类型成员变量a和b是在栈中被分配的?你要注意,a和b不是在main函数中直接声明的,而是类的成员变量啊……
其实,我可以把意思说的更明白些:
如果类与类之间出现了组合关系时,当调用类被实例化时,被引用类的指针或者说引用符号,到底是在栈中还是堆中分配的?注意:被引用的类,并非是直接在函数中定义的局部变量。特请注意!!!!
sorry,没看清-_-#,.成员变量全在堆里没错,这个我的说法有问题。方法体里的变量指针在栈里,只出现在方法运行时也就是说,new A()时,里面的类型成员变量a和b的引用和对象都被分配在堆里了?创建A这个对象的时候,在堆里会分配A所需的内存,包含了a、b这两个成员变量。注意ab都是基础类型,不是对象。
兄弟,你确定当执行new A()时,a实例中的类型成员变量a和b是在栈中被分配的?你要注意,a和b不是在main函数中直接声明的,而是类的成员变量啊……
其实,我可以把意思说的更明白些:
如果类与类之间出现了组合关系时,当调用类被实例化时,被引用类的指针或者说引用符号,到底是在栈中还是堆中分配的?注意:被引用的类,并非是直接在函数中定义的局部变量。特请注意!!!!
sorry,没看清-_-#,.成员变量全在堆里没错,这个我的说法有问题。方法体里的变量指针在栈里,只出现在方法运行时也就是说,new A()时,里面的类型成员变量a和b的引用和对象都被分配在堆里了?创建A这个对象的时候,在堆里会分配A所需的内存,包含了a、b这两个成员变量。注意ab都是基础类型,不是对象。我的类型定义错了,里面包含了重名的a和b,一个是int型的,一个是复合类型的。假设把复合类型的a和b的名字改成e和f,修改后如下:
class A{
int a,b;
A e,f;
//......
}
则修改后,当执行new A()时,是不是要在堆中分配4×6=64个字节的内存空间了?
兄弟,你确定当执行new A()时,a实例中的类型成员变量a和b是在栈中被分配的?你要注意,a和b不是在main函数中直接声明的,而是类的成员变量啊……
其实,我可以把意思说的更明白些:
如果类与类之间出现了组合关系时,当调用类被实例化时,被引用类的指针或者说引用符号,到底是在栈中还是堆中分配的?注意:被引用的类,并非是直接在函数中定义的局部变量。特请注意!!!!
sorry,没看清-_-#,.成员变量全在堆里没错,这个我的说法有问题。方法体里的变量指针在栈里,只出现在方法运行时也就是说,new A()时,里面的类型成员变量a和b的引用和对象都被分配在堆里了?创建A这个对象的时候,在堆里会分配A所需的内存,包含了a、b这两个成员变量。注意ab都是基础类型,不是对象。我的类型定义错了,里面包含了重名的a和b,一个是int型的,一个是复合类型的。假设把复合类型的a和b的名字改成e和f,修改后如下:
class A{
int a,b;
A e,f;
//......
}
则修改后,当执行new A()时,是不是要在堆中分配4×6=64个字节的内存空间了?
-_-#...果然是搞c++的,我不太记得int占多少空间了,总之创建A的时候会给A分配内存,这块内存里包含了ab两个int的长度,和两个指针ef(你可以这样理解),由于ef没有被初始化,实际上是指向null的
还是这位大神的回答非常精准,看出了问题的本质。
其实我看了一些书之后,也认为应该是这样分配的。只是网上绝大部分博客或者书籍中都没有对这类问题的分析,网上绝大多数的博客都在分析这样的一个简单的问题:如果在函数中实例化一个类,那么内存是如何分配的?这个问题太简单了,都说烂了。不过我还不是太确定我的看法,和你的看法,到底是否正确。不知这位大神能否想出一些代码用于测试?或者帮忙分析下编译后的代码,以进行论证?
十分期待您的进一步分析和讨论。
你要我写代码验证,我真没那水平得出一个demo就能说明整个对象详细内存布局,不过我们可以从类的加载、初始化到对象的内存分配一步一步地进行分析:
一、类在主动使用时才进行初始化包括:
1.创建类的新实例;
2.调用类中声明的静态非常量字段;
3.调用类中声明的静态方法;
4.使用反射方法生成类的对象;
5.初始化一个类的子类;
6.指定一个类作为启动类
但是有几点需要注意:
1.通过子类访问父类的静态非常量字段只会初始化父类,不会初始化子类;
2.访问常量静态字段不会进行初始化;
3.初始化接口并不要求父接口完成初始化;
上面的我们都可以自己写测试代码来验证,由于比较简单,我就不贴代码了 ;二、类的加载,类加载分为3个步骤:
1.通过全限定名找到定义类的二进制文件(即class文件);
2.将二进制文件中的静态储存结构转为为方法区的运行时数据结构;
3.生成一个代表类的Class对象;这个无法通过代码区验证,但是可以结合字节码和Java虚拟机内存的变化来观察,
字节码可以使用javap来生成,虚拟机的内存变化可以通过jconsole来观察;三、类的验证不详述,因为不会涉及到内存的分配;
四、类的准备是为类变量分配内存,如果是常量则在常量池中,如果是对象是在堆中;
五、类的解析不详述,因为不会涉及到内存的分配;
六、类的初始化,类的初始化是通过类构造器来实现的,主要是static语句块的合并;
七、分配对象内存,大小由对象的属性值和Java虚拟机自身的对象内存布局来确定,如果对C有了解,
我们把对象看成是结构体的类型数据综上所述,我们可以大致理解为:
1.可以把对象看成C语言的结构体,这样方便我们理解,当然对象还包含其他的信息,如对象头、对其填充等等;
2.有关类的信息的都在方法中,包括静态变量、常量、方法体的字节码等等;
3.局部变量都在栈中、对象都在堆中、常量都在常量池(方法区的一部分)中;我们可以通过对象的访问,来进一步加深理解,如下图:
兄弟,你确定当执行new A()时,a实例中的类型成员变量a和b是在栈中被分配的?你要注意,a和b不是在main函数中直接声明的,而是类的成员变量啊……
其实,我可以把意思说的更明白些:
如果类与类之间出现了组合关系时,当调用类被实例化时,被引用类的指针或者说引用符号,到底是在栈中还是堆中分配的?注意:被引用的类,并非是直接在函数中定义的局部变量。特请注意!!!!
sorry,没看清-_-#,.成员变量全在堆里没错,这个我的说法有问题。方法体里的变量指针在栈里,只出现在方法运行时也就是说,new A()时,里面的类型成员变量a和b的引用和对象都被分配在堆里了?创建A这个对象的时候,在堆里会分配A所需的内存,包含了a、b这两个成员变量。注意ab都是基础类型,不是对象。我的类型定义错了,里面包含了重名的a和b,一个是int型的,一个是复合类型的。假设把复合类型的a和b的名字改成e和f,修改后如下:
class A{
int a,b;
A e,f;
//......
}
则修改后,当执行new A()时,是不是要在堆中分配4×6=64个字节的内存空间了?
-_-#...果然是搞c++的,我不太记得int占多少空间了,总之创建A的时候会给A分配内存,这块内存里包含了ab两个int的长度,和两个指针ef(你可以这样理解),由于ef没有被初始化,实际上是指向null的说到这里,我突然想起一个问题来。如果e,f不是null,而是直接实例化,例如:
class A{
int a,b;
A e=new A(), f=new A();
//......
}
如果是这样,main函数中执行new A()后,A内部的e,f两个变量也要实例化,并要分配内存空间。但是执行e=new A()后,在堆中又为new A分配了一个空间。结果这个new A中又有两个实例变量e,f,于是又执行e=new A()……这样岂不是会一直循环下去么?内存很快就被耗尽了。不知道这种情况如何解决?或者jvm有啥规范?
还是这位大神的回答非常精准,看出了问题的本质。
其实我看了一些书之后,也认为应该是这样分配的。只是网上绝大部分博客或者书籍中都没有对这类问题的分析,网上绝大多数的博客都在分析这样的一个简单的问题:如果在函数中实例化一个类,那么内存是如何分配的?这个问题太简单了,都说烂了。不过我还不是太确定我的看法,和你的看法,到底是否正确。不知这位大神能否想出一些代码用于测试?或者帮忙分析下编译后的代码,以进行论证?
十分期待您的进一步分析和讨论。
你要我写代码验证,我真没那水平得出一个demo就能说明整个对象详细内存布局,不过我们可以从类的加载、初始化到对象的内存分配一步一步地进行分析:
一、类在主动使用时才进行初始化包括:
1.创建类的新实例;
2.调用类中声明的静态非常量字段;
3.调用类中声明的静态方法;
4.使用反射方法生成类的对象;
5.初始化一个类的子类;
6.指定一个类作为启动类
但是有几点需要注意:
1.通过子类访问父类的静态非常量字段只会初始化父类,不会初始化子类;
2.访问常量静态字段不会进行初始化;
3.初始化接口并不要求父接口完成初始化;
上面的我们都可以自己写测试代码来验证,由于比较简单,我就不贴代码了 ;二、类的加载,类加载分为3个步骤:
1.通过全限定名找到定义类的二进制文件(即class文件);
2.将二进制文件中的静态储存结构转为为方法区的运行时数据结构;
3.生成一个代表类的Class对象;这个无法通过代码区验证,但是可以结合字节码和Java虚拟机内存的变化来观察,
字节码可以使用javap来生成,虚拟机的内存变化可以通过jconsole来观察;三、类的验证不详述,因为不会涉及到内存的分配;
四、类的准备是为类变量分配内存,如果是常量则在常量池中,如果是对象是在堆中;
五、类的解析不详述,因为不会涉及到内存的分配;
六、类的初始化,类的初始化是通过类构造器来实现的,主要是static语句块的合并;
七、分配对象内存,大小由对象的属性值和Java虚拟机自身的对象内存布局来确定,如果对C有了解,
我们把对象看成是结构体的类型数据综上所述,我们可以大致理解为:
1.可以把对象看成C语言的结构体,这样方便我们理解,当然对象还包含其他的信息,如对象头、对其填充等等;
2.有关类的信息的都在方法中,包括静态变量、常量、方法体的字节码等等;
3.局部变量都在栈中、对象都在堆中、常量都在常量池(方法区的一部分)中;我们可以通过对象的访问,来进一步加深理解,如下图:
真够详细的呵呵