标签:全局数据区 内存分析 目标 十六进制 overflow 存储结构 person 蓝色 程序代码
注:蓝色高亮代表还要查写的东西;红色字体用于阅读时提醒。
----------------------------------------------------Hello!-----------------------------------------------------------How-----------------------------------------------------------------are----------------------------------------------------------------------------------you?------------------------------------------------------------------------
Q:请解释PATH和CLASSPATH的区别?
A:PATH是系统定义的环境属性,用于定义所有可执行程序的路径;
CLASSPATH是JVM定义的属性,在用java命令解释程序时会自动找到CLASSPATH的路径,进行类的加载。
对象内存分析
类本身属于引用数据类型,对于引用数据类型,必须对其进行内存分析。
堆内存:保存的是对象的具体属性信息;
栈内存:保存堆内存的地址(可理解为:对象名称)。
一块栈内存只能保存一块对应的堆内存地址。
第二种定义方法
Person per=null;//声明对象
per=new Person();//实例化对象
当没有实例化时,运行会发生 NullPointException;因为使用了没有开辟堆内存空间的引用对象。
(1)一块堆内存空间可以被多个栈内存所指向;
(2)如果一块堆内存空间没有任何栈内存指向,它会变成垃圾空间,所有垃圾空间会被GC回收并释放。垃圾回收时间时不确定的,要少产生。
构造方法:
方法名称与类名称相同;
如果一个类中没有构造方法,系统会自动提供一个无参构造。(所以,所有类中,肯定都有构造方法)。
作用:如果希望在对象实例化时传递一些参数,可用。
Q:既然构造方法没有返回值,那为什么不用void声明?
A:构造方法只在对象声明时调用一次;不同方法可以利用对象调用多次,如果是public void Person(){};这表示一个普通方法。
static:
主要用于描述全局概念;修改一个对象属性时,所有对象属性都会发生改变。对于这样的公共属性,不保存在栈,堆中,而保存在全局数据区中。
对于static定义的属性,可以用类名称直接调用。
所有非static属性,在对象实例化的时候才会进行内存的分配;
所有static属性,可以在没有实例化对象的时候进行调用。
使用情况:如果一个类中没有任何属性,那么这个类中不需要定义普通方法,只需要定义static方法。因为这样可以减少开辟无用的堆内存空间。
单例模式:
1.将该类的构造方法私有化,目的是禁止其他程序创建该类的对象;
2.在本类中自定义1个对象:
3.提供一个访问该类自定义对象的成员方法。
线程的几种可用状态:
1.新建;
2.可运行(runnable):线程对象创建后,其他线程(比如main)调用了该对象的start()方法,该线程位于可运行线程池中,等待被线程调度选中,获得CPU适用权;
3.运行(running):可运行的线程获得CPU的时间片(timeslide),执行程序代码;
4.阻塞(block):线程因为某原因放弃了CPU的适用权。阻塞分三种:
4.1等待~,运行的线程执行o.wait()方法,JVM会把该线程放入等待队列中;
4.2同步~,运行的线程在获取同步锁时,该同步锁被别的线程占用,JVM会把线程放到锁池中;
4.3其他~,运行的线程执行Thread.sleep(Long ms)或t.join();
5.死亡:线程run()或main()方法结束,或者由于异常退出了run()。死亡的线程不可再次复生。
死锁:
两个或以上的线程在执行过程中,因争夺资源而造成的一种相互等待现象。
产生原因:系统资源不足;进程运行顺序不合适;资源分配不当;
死锁的4个必要条件:
互斥,一个资源每次只能被一个进程使用;
请求与保持,1个进程因请求资源而阻塞,对以获得的资源保持不放;
不可剥夺:进程已获得的资源,在未使用完成前不能强行剥夺;
循环等待:若干线程形成一种头尾相接的循环等待资源关系;
-------------------------------------------------------------------------------------------------------------------------------------------------------------:)-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// 垃圾回收这里又忘了,把印象笔记里的重新抄一篇。完整版请参阅:http://blog.csdn.net/u012422829/article/details/46580893
java内存区域分析
1.运行时数据区域分析
运行时数据区域分为两部分,一部分时线程共享的(方法区,堆),另一部分时线程私有的(虚拟机栈,本地方法栈,程序计数器)
(1) 程序计数器:一块较小的内存空间,可看作是,当前线程所执行的字节码的行号指示器。
如果线程正在执行一个Java方法,计数器值为当前执行时虚拟机字节码指令地址;如果执行的时native方法,计数器值为空。
(注:被native修饰的方法叫本地方法,本地方法意味着和平台有关,移植性不高,native方法在JVM运行时数据区和其他方法不一样,它有专门的本地方法栈。native方法主要用于加载文件和动态链接库。是唯一不会出现OutOfMemoryError的区域)
(2)虚拟机栈:描述的是Java方法执行时的内存模型。
每个方法方法执行时都会创建一个栈帧,用于存储局部变量,操作数栈,动态链接,方法出口等信息。每个方法从调用到执行完的过程,都对应一个栈帧在虚拟机中入栈到出栈的过程。
(3)本地方法栈:作用与虚拟机栈类似。
区别:虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,本地方法栈为虚拟机使用到的native方法服务,也会抛出StackOverFlowError和OutOfMemoryError异常
(4) java堆:被所有线程共享,在虚拟机启动时创建,它的目的是存放对象实例,几乎所有对象(和数组)都在这里分配内存。java堆是垃圾收集器管理的主要区域,也被称为GC堆。~处于物理上不连续的内存空间,只要逻辑上连续即可。
(5)方法区:所有线程共享,存储已被虚拟机加载的类信息,常量,静态变量,及时编译器编译后的代码数据。虽然有”永久代“之称,任然存在内存回收,主要针对常量池的回收和对类型的卸载,也会抛出OutOfMemoryError异常。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------O_o------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
对象的创建
虚拟机遇到new指令时,先检查虚拟机是否加载了你要new的这个类(检查这个指令的参数能否在常量池中定位到一个类符号的引用),如果没加载,必须先执行相应的类的加载。
然后,为新生对象分配内存。
内存分配之后,虚拟机需要将内存空间都初始化为0。
接下来,对对象做必要的设置,例如,这个对象是哪个类的实例?如何才能找到类的元数据信息,对象的哈希码等,这些信息都存放在对象的头之中。
最后,执行程序员的意愿初始化。
类的加载机制
虚拟机把描述类的数据从class文件加载到内存中,并对数据进行校验,转换解析和初始化;最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。
在Java中,类的加载,连接和初始化过程都是在程序运行期间完成的。
类从被加载到虚拟机内存中开始,到卸载出内存为止,整个生命周期包括:加载,【验证,准备,解析】(注:这三个动作称为:连接),初始化,使用和卸载。注:解析的顺序不是固定的,有时候能在初始化结束后才开始,以支持Java动态绑定。
下面写初始化时机
类加载过程:
1.加载
该阶段要完成以下三件事:
(1)通过一个类的全限定名来获取此类的二进制流
(2)将这个字节流所代表的静态存储结构转化为方法区运行时的数据结构
(3)在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口
2.验证
目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,因为Class文件的来源不一定时编译产生。甚至可以直接用十六进制编辑器直接编写。所以,如果不检查输入的字节流,对其完全信任的话,很有可能因为载入有害的字节流而导致系统崩溃
(大致可以分为4个阶段的检验 :1.文件格式验证 2.元数据验证 3.字节码验证 4.符号验证)
3.准备
是正式为类变量(被static修饰的变量)设置类变量的初始值(通常情况下数据类型值为0,具体赋值阶段时初始化阶段)。这些变量所使用的内存都将在方法区中进行分配,如果字段属性表中包含ConstantValue属性,那么准备阶段会设置为该值。
例如:public final static int a =123;
4.解析
是虚拟机将常量池中的符号引用替换为直接引用的过程
在Java中,一个Java类会编译成一个class文件,在编译时Java类并不知道引用类的实际地址,因此只能使用符号引用来代替。比如:org.simple.People类引用org.simple.Tool类,在编译时People类并不知道Tool类的实际内存地址,因此只能使用符号org.simple.Tool(假设)来表示Tool类的地址。而在类装载器装载People类时,此时可以通过虚拟机来获取Tool类的实际内存地址。因此便可以将符号org.simple.Tool替换为Tool类的实际地址,即直接引用。(注:直接引用与虚拟机实现的内存布局相关,引用目标必须加载到内存中;符号引用则不必须)。
5.初始化
在之前的阶段,除了加载阶段用户可以自定义类加载参与,其他阶段完全由虚拟机主导和控制,直到初始化阶段,才真正执行类定义的Java程序代码。
虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何获取所需要的类。实现这个动作的代码模块称为类加载器。
标签:全局数据区 内存分析 目标 十六进制 overflow 存储结构 person 蓝色 程序代码
原文地址:https://www.cnblogs.com/alatar16/p/8728923.html