java内存区域和管理机制
java运行时数据区域划分
以下大部分来自《深入理解java虚拟机》
java虚拟机在执行java程序的时候会把他分为若干区域(栈、堆、方法区),具体如下。
1、线程私有区域
1-1 线程与进程
1、进程:在计算机内存中的运行程序,有属于一块内存空间分配 给他,如果没记错的话好像进程切换时对应的单核和多核,就是同一时间只能处理一个进程,但是由于切换的速度快,我们好像认为它能处理多个(希望指正)。
2、线程:一个进程包含了多个线程,是cpu调度和分配的基本单位,就是线程在抢cpu的时间片,谁抢到就执行。
1-2、创建线程的两种方式
1、创建线程对象
public class CreateThread01 {
public static void main(String[] args) {
Thread t1 = new Thread01();
t1.setName("线程1");
t1.start();
for(int i=0;i<20;i++){
System.out.print(i+" ");
}
// t1.run();
}
}
class Thread01 extends Thread{
@Override
public void run() {
for(int i=5;i<30;i++){
System.out.print(""+"线程1"+i+" ");
}
}
}
这里用start()开辟一个线程栈,两个线程争抢时间片,有时候是主线程(main)抢到,有时候是线程1,
如果是直接调用run(),就是调用对象方法,并没有开辟空间,所以也不是多线程
public class CreateThread01 {
public static void main(String[] args) {
Thread t1 = new Thread01();
t1.run();
// t1.start();
for(int i=0;i<20;i++){
System.out.print(" "+i+" ");
}
}
}
class Thread01 extends Thread{
@Override
public void run() {
for(int i=5;i<30;i++){
System.out.print(""+"线程"+i+" ");
}
}
}
2、继承Runable接口
public class ThreadTest03 {
public static void main(String[] args) {
Thread1 t1 = new Thread1();
t1.run();
}
}
class Thread1 implements Runnable{
@Override
public void run() {
for(int i=0;i<10;i++){
System.out.println(i);
}
}
}
也可以用匿名内部类的方式创建,
匿名内部类来创建
public class CreateThread02 {
public static void main(String[] args) {
new Runnable(){
@Override
public void run() {
for(int i=0;i<6;i++){
System.out.println(i);
}
}
}.run();
}
}
1-2、程序计数器
1、程序计数器是一块内存空间,对于编译过后的字节码文件,指示程序执行到哪一行
2、每一个线程就有一个程序计数器
3、
native方法:就不是java程序,通过java调用的非java程序
1-3 、java虚拟机栈
栈这种数据结构是先入后出,就像你往一个月饼盒里面一直向上堆月饼
每个java方法执行的时候就会有一个创建一个栈帧(一个月饼),*存储局部变量表(这个方法所需要的数据变量和对象地址),操作栈、方法出口等,*你发现要拿最底下的月饼,就需要把上面的都拿出来
这个地方有两个异常
就是月饼不够放了StackOverflowError,在上面加个盒子还不够放OutOfMemoryError
1-4 本地方法栈
就是上面说的native方法就是在这个栈中(非java)
2-1 java堆
1、java堆属于线程共享区,也是java虚拟机中内存最大的区域,几乎所有的对象实例都是在这里分配 内存(简单点***对象 a = new 对象()***;这个对象就在这个区域,而栈中放的就是堆中对象的地址)
2、java堆是垃圾回收的主要地方(GC在后面几章会继续说)
3、堆内存可以不连续,也会有outOfMemory异常
3-1 方法区
也就是文件.class转化后的java.lang.Class对象存放的地方(这里因该是和反射有关),有了这个文件才能创建实例对象。
3-1运行时常量池
1、是方法区的一部分
2、不仅是编译后的常量放在这,运行时的也可以放这
public class CLTest01 {
public static void main(String[] args) {
String s = new String("boy");
String s1 = "boy";
System.out.println(s==s1); //false
System.out.println(s1==s.intern()); //true
}
}
可以看到其中s为堆中内存地址,’‘==’‘比较值,s1在常量池中,但是通过intern()使其也转化到常量池中
感觉也就这么多了,各位大佬批评指正!