发表于: 2018-02-07 23:04:12

1 787


今日完成

1.java内存分配学习;

   方法区:又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。

       方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。

            今天查看资料发量池存放在堆中还是存放在方法区中有不同的说法

           ----运行时常量池都分配在 Java 虚拟机的方法区之中;-----

                   这和昨天查到的说法:------常量池存放于堆中-----不同

                 明天查资料验证;

  查到资料中提到:方法区逻辑上属于堆的一部分,但是为了与堆进行区分,通常又叫“非堆”。


   

     Java的GC((Garbage Collection)机制:垃圾回收机制:

     Java的内存回收主要在Java的堆上进行的。

常用垃圾收集算法

1. 标记-清除算法

   先标记需要所有回收的对象,然后回收所有需要回收的对象;

   缺点,造成内存块在回收之后没有连续性,当需要一大块的内存时,系统无法进行分配;

    

    

2. 标记-清除-压缩

    优化了上一种算法的,在清除之后对内存进行了压缩,保证了内存块的连续性,但是由于这种压缩是通过不停的内存间的拷贝和复制进行的,所以性能会非常差;

3.标记-清除-复制

     这种算法会将内存空间分配成两块相同的区域1和2。当内存回收的时候,将2中的内存块拷贝到1中,然后一次性清空1。

 

  java的分代算法:

   JVM区域总体分两类,heap区和非heap区。heap区又分:Eden Space(伊甸园)、Survivor Space(幸存者区)、Tenured Gen(老年代-养老区)。 非heap区又分:Code Cache(代码缓存区)、Perm Gen(永久代)、Jvm Stack(java虚拟机栈)、Local Method Statck(本地方法栈)。 

a.新生代(young generation)和老生代(Old Generation);

    Java的新生代中,对象的存活率低,存活期期会相对会比较短一些,所以可以选用复制算法来进行内存回收。

    Java的老生代中,对象的存活率比较高,并且相对存活期比较长一些,可以采用标记-清除-压缩的算法来进行内存回收。

    

   其中,通常新生代分为Eden Space(伊甸园)和2个Survivor Space(幸存者区)

   Java的方法区间和常量池我们一般称为永久代(在JDK8中永生代已经完全消失,转而使用元空间。而元空间是直接存在内存中,不在java虚拟机中的,因此元空间依赖于内存大小。

    Java的对象会优先在Eden Space(伊甸园)上分配,这些对象经过第一次Minor GC后,如果仍然存活,将会被移到Survivor区。(从新生代(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC对象在Survivor区中每熬过一次Minor GC,年龄就会增加1岁,当它的年龄增加到一定程度时,就会被移动到老年代中。)

在GC开始的时候,对象只会存在于Eden区和名为“From”的Survivor区(上图中Survivor2区),Survivor区“To”(上图中Sruvivor2区)是空的。紧接着进行GC,Eden区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置)来决定去向。没有达到阈值的对象会被复制到“To”区域。经过这次GC后,Eden区和From区已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”(上图中Surviror2区)就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎样,都会保证名为To的Survivor区域是空的。Minor GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。

 

2.多线程学习;

  join方法、yield方法的学习和练习;

public class Runnabletest1 implements Runnable {
private String name;
    private int s=10;

   public Runnabletest1(String name) {

this.name = name;
   }

//重新run方法
   public void  run() {
System.out.println("线程运行开始");
       for (int i = 0; i < 5; i++) {
s=s-1;
           System.out.println(name+" 子线程运行  "+s);
           try {
sleep(1000);
           } catch (InterruptedException e) {
e.printStackTrace();
           }
}
System.out.println(name+" thread complated");
   }

public static void main(String[] args) {
System.out.println("mainThread start");
      Runnabletest1 A1=new Runnabletest1("a1");
       Runnabletest1 A2=new Runnabletest1("a2");
       Thread a1=new Thread(A1);
       Thread a2=new Thread(A2);
       a1.start();
       a2.start();
       try {
a1.join();
       } catch (InterruptedException e) {
e.printStackTrace();
       }
try {
a2.join();
       } catch (InterruptedException e) {
e.printStackTrace();
       }
System.out.println("mainThread completed");
   }
}



public class YieldTest implements Runnable {
private String name;
   private Thread thread;
   public YieldTest(String name) {
this.name = name;
   }

public void run() {

System.out.println(name+"子线程开始运行");
        synchronized(""){
for(int i=0;i<10;i++) {
System.out.println(name + "  线程运行  " + i);
           if(i == 30){
new Thread().yield();
//问题在这里

           }
try {
sleep(2000);
           } catch (InterruptedException e) {
e.printStackTrace();
           }}
}
System.out.println(name+" 子线程结束");
   }

public static void main(String[] args) {
System.out.println("主程序开始");

       YieldTest A1=new YieldTest("a1");
       YieldTest A2=new YieldTest("a2");
       Thread a1=new Thread(A1);
       Thread a2=new Thread(A2);
       a1.start();
       a2.start();

       try {
a1.join();
       } catch (InterruptedException e) {
e.printStackTrace();
       }
try {
a2.join();
       } catch (InterruptedException e) {
e.printStackTrace();
       }
System.out.println("主线程结束");
   }
}


public class Threadtest1 extends Thread {
private String name;

   public Threadtest1(String name) {
super(name);
       this.name = name;
   }

public void run() {//重写run方法
      for(int i=0;i<50;i++) {
          System.out.println(name + i);
          if(i == 30){
this.yield();

          }
      }
  }
public static void main(String[] args) {
//实例化对象
      Threadtest1 a=new Threadtest1("A");
      Threadtest1 b=new Threadtest1("B") ;
      //调用start方法启动线程
      a.start();
      b.start();
  }
}

明天计划

1.学习多线程;

 synchronized、wait、notify等方法的运用;

收获

学习了java的内存分配和GC机制,写代码时思路更为清晰;

学习了多线程的一些知识点;

遇到问题

上面第二段代码中,使用this.yield()会报错,这里自己分析了下:这里实现了Runnable接口,但是Runnable接口也是通过Thread类来实现多线程。这里的run()方法与Thread类中的方法相同,但是Runnable接口中没有yield方法,所以重写中需要实例化Thread类的对象。虽然这里没有再报错,但是还是有点想不通,感觉上面的代码并不能明确体现出yield方法的作用;



返回列表 返回列表
评论

    分享到