码迷,mamicode.com
首页 > 其他好文 > 详细

面向对象(一):基础分析

时间:2015-04-08 21:35:56      阅读:204      评论:0      收藏:0      [点我收藏+]

标签:面向对象   内存分配   内存管理   虚拟机   对象的内存分配   

一、Java中的内存分配

技术分享


Java 程序在运行时,需要在内存中分配空间。为提高运算效率,对内存空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式与内存管理方式。

1、Class Loader 类加载器
类加载器的作用是加载类文件到内存,编程字节码。比如编写一个HelloWord.java程序,然后通过javac编译成class文件, Class Loader承担加载到内存的责任。

2、STACK 栈:存放局部变量。
  • 数据用完就释放,一定是脱离了它的作用域。
  • Java中,栈的大小通过-Xss来设置,当栈中存储数据比较多时,需要适当调大这个值,否则会出现java.lang.StackOverflowError异常。常见的出现这个异常的是无法返回的递归,因为此时栈中保存的信息都是方法返回的记录点。
3、HEAP 堆:存储new()出来的东西。
  • 每一个new出来的东西都有引用值。
  • 每一个变量都有默认值
    • byte、shot、int、long 0
    • float、double、0.0
    • char  ‘\u0000‘ 代表空字符
    • boolean false
    • 引用类型 null
  • 使用完毕就变成了垃圾,但是并没有立即回收。会在垃圾回收器空闲的时候回收。
  • 堆内存分为三部分:
    • Permanent Space 永久存储区 。
      • 永久存储区是一个常驻内存区域,用于存放JDK自身所携带的Class,Interface的元数据,也就是说它存储的是运行环境必须的类信息,被装载进此区域的数据是不会被垃圾回收器回收掉的,关闭JVM才会释放此区域所占用的内存。
    • Young Generation Space 新生区 。
      • 新生区是类的诞生、成长、消亡的区域,一个类在这里产生,应用,最后被垃圾回收器收集,结束生命。
      • 新生区又分为两部分:伊甸区(Eden space)和幸存者区(Survivor pace)。
        • 所有的类都是在伊甸区被new出来的。幸存区有两个: 0区(Survivor 0 space)和1区(Survivor 1 space)。
        • 当伊甸园的空间用完时,程序又需要创建对象,JVM的垃圾回收器将对伊甸园区进行垃圾回收,将伊甸园区中的不再被其他对象所引用的对象进行销毁。然后将伊甸园中的剩余对象移动到幸存0区。若幸存0区也满了,再对该区进行垃圾回收,然后移动到1区。那如果1区也满了呢?再移动到养老区。
    • Tenure generation space养老区 。养老区用于保存从新生区筛选出来的JAVA对象,一般池对象都在这个区域活跃。
技术分享

4、Method Area 方法区
  • 方法区是被所有线程共享,该区域保存所有字段和方法字节码,以及一些特殊方法如构造函数,接口代码也在此定义。
  • static 变量存放于这边,用于共享。
  • String 字符串常量池也在这边。
5、本地方法区(和系统相关)
6、寄存器(给CPU使用)

技术分享


二、一个对象的内存分配

1、类加载器加载class文件变为字节码存入【方法区】,运行main方法进【栈】。
2、new一个对象,成员变量入【堆】,方法仍存放在【方法区】。
3、方法的调用,从【方法区】加载方法入【栈】,然后调用。执行完毕,从【栈】中被删除。
4、再new同一个对象,会在【堆】张开辟另一块位置,成员变量入【堆】,方法不动。
5、执行完毕,最后main方法,从【栈】中被删除。
6、内存中类的class文件只有一份,即字节码是唯一的。
7、static性质的也只有一份,所以多线程锁要同步static ,可以锁定字节码。


图1,1个对象

技术分享


图2,2个对象


技术分享


图3,对象赋值


技术分享


三、一个对象的内存大小

1、基本数据的类型的大小是固定的,这里就不多说了。
2、对于非基本类型的Java对象,其大小就值得商榷。 在Java中,一个空Object对象的大小是8byte,这个大小只是保存堆中一个没有任何属性的对象的大小。如 
<span style="font-family:Arial;font-size:18px;">Object ob = new Object();</span>

3、这样在程序中完成了一个Java对象的生命,但是它所占的空间为:4byte+8byte。4byte是Java栈中保存引用的所需要的空间。而8byte则是Java堆中对象的信息。因为所有的Java非基本类型的对象都需要默认继承Object对象,因此不论什么样的Java对象,其大小都必须是大于8byte。

4、有了Object对象的大小,我们就可以计算其他对象的大小了。
<span style="font-family:Arial;font-size:18px;">Class NewObject {
    int count;
    boolean flag;
    Object ob;
}</span>

其大小为:空对象大小(8byte)+int大小(4byte)+Boolean大小(1byte)+空Object引用的大小 (4byte)=17byte。但是因为Java在对对象内存分配时都是以8的整数倍来分,因此大于17byte的最接近8的整数倍的是24,因此此对象的大小为24byte。

5、这里需要注意一下基本类型的包装类型的大小。因为这种包装类型已经成为对象了,因此需要把他们作为对象来看待。包装类型的大小至少是12byte(声明一个空Object至少需要的空间),而且12byte没有包含任何有效信息,同时,因为Java对象大小是8的整数倍,因此一个基本类型包装类的大小至少是16byte。这个内存占用是很恐怖的,它是使用基本类型的N倍(N>2),有些类型的内存占用更是夸张(随便想下就知道了)。因此,可能的话应尽量少使用包装类。在JDK5.0以后,因为加入了自动类型装换,因此,Java虚拟机会在存储方面进行相应的优化。


四、Java中参数传递问题

(一)论点:Java中只有值传递。
1、基本类型,传的是值,所以不会变。String的效果与基本类型一致。
2、引用类型,传的是地址值,所以会变化。

(二)分析:
1、Java虚拟机中,数据类型可以分为两类:基本类型和引用类型。
  • 基本类型的变量保存原始值,即:他代表的值就是数值本身;
    • 基本类型包括:byte,short,int,long,char,float,double,Boolean,returnAddress 
  • 引用类型的变量保存引用值(地址值)。“引用值”代表了某个对象的引用,而不是对象本身,对象本身存放在这个引用值所表示的地址位置。
    • 引用类型包括:类类型,接口类型和数组。
2、【栈】是运行时的单位,而【堆】是存储的单位。
  • 【栈】解决程序的运行问题,即程序如何执行,或者说如何处理数据,调用方法;
  • 【堆】解决的是数据存储的问题,即数据怎么放、放在哪儿。
3、程序运行永远都是在【栈】中进行的,因而参数传递时,只存在传递基本类型和对象引用的问题。不会直接传对象本身。

4、Java在方法调用传递参数时,因为没有指针,所以它都是进行传值调用(这点可以参考C的传值调用)。

5、 在【运行栈】中,基本类型和引用的处理是一样的,都是传值,所以,如果是传引用的方法调用,也同时可以理解为“传引用值”的传值调用,即引用的处理跟基本类型是完全一样的。但是当进入被调用方法时,被传递的这个引用的值,被程序解释(或者查找)到【堆】中的对象,这个时候才对应到真正的对象。如果此时进行修改,修改的是引用对应的对象,而不是引用本身,即:修改的是【堆】中的数据。所以这个修改是可以保持的了。

6、对象,从某种意义上说,是由基本类型组成的。可以把一个对象看作为一棵树,对象的属性如果还是对象,则还是一颗树(即非叶子节点),基本类型则为树的叶子节点。程序参数传递时,被传递的值本身都是不能进行修改的,但是,如果这个值是一个非叶子节点(即一个对象引用),则可以修改这个节点下面的所有内容。

技术分享


补充:方法重载

1、特点

1)与返回值类型无关,只看方法名和参数列表。
2)在调用时,虚拟机通过参数列表的不同来区分同名方法。



面向对象(一):基础分析

标签:面向对象   内存分配   内存管理   虚拟机   对象的内存分配   

原文地址:http://blog.csdn.net/u012228718/article/details/44926003

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!