zoukankan      html  css  js  c++  java
  • JVM培训作业第二周

    1. jre的运行时主要jar文件rt.jar都很大,这导致了用java做的桌面客户端程序很难发布绑定jre发布。这在很大程度上限制了java桌面软件 的分发。可是,jre并不是在所有的用户计算机上都有安装,即使安装了,也未必我们期望的版本。因此,对jre做精简,减少体积是有必要的。请你给出一个 方案,来说说如何给jre减肥,以方便我们的桌面程序绑定jre发布。并给出一个基本的实现。对这个实现的要求是:对于任意给定java程序A,应用你的 方案和实现,可以从一个完整的jre中,抽取这个程序A的必要部分,从而实现最小体积的发布。在本题中,要求你详述你的方案,并提交你实现的代码。

    整个过程分为两步:

    1. 找出程序依赖的所有class类文件,并整理出一个class依赖列表,具体步骤如下:

      加入参数-XX:+TraceClassLoading, 启动桌面程序并且重定向console流到一个文件比如classdepenency.txt.
      然后对程序做一个完整的回归测试,确保所有的功能点都已经用到了,目的是为了完整的加载所有的依赖。
      因为有些依赖class可能是运行时期通过反射或者Class.forName()来加载的,这些类只有在代码被运行的时候classloader才会加载对应的依赖。
      程序测试完毕后,用编辑工具比如notepad++对classdepenency.txt做一个简单的筛选,去掉与classloading无关的console信息。

       只留如下所示的classloader加载rt.jar中类的信息。
      
    [Loaded java.util.logging.LogManager$2 from F:Program FilesJavajdk1.7.0_51jrelibrt.jar]
    [Loaded java.util.Collections$EmptyEnumeration from F:Program FilesJavajdk1.7.0_51jrelibrt.jar]
    [Loaded java.util.EventObject from F:Program FilesJavajdk1.7.0_51jrelibrt.jar]
    [Loaded java.beans.PropertyChangeEvent from F:Program FilesJavajdk1.7.0_51jrelibrt.jar]
    [Loaded sun.util.logging.PlatformLogger from F:Program FilesJavajdk1.7.0_51jrelibrt.jar]


    2. 写个小程序从JRE里面的rt.jar抽取出上一步筛选后的classdepenency.txt文件里记录的所有类.下面是程序的代码.

    01 package test;
    02 import java.io.BufferedReader;
    03 import java.io.FileInputStream;
    04 import java.io.FileOutputStream;
    05 import java.io.InputStream;
    06 import java.io.InputStreamReader;
    07 import java.util.ArrayList;
    08 import java.util.List;
    09 import java.util.jar.JarEntry;
    10 import java.util.jar.JarFile;
    11 import java.util.jar.JarInputStream;
    12 import java.util.jar.JarOutputStream;
    13  
    14  
    15 public class ReduceJRE {
    16  
    17     public static void main(String[] args) throws Exception {
    18         String mainJar = null;
    19         String classDenpdencyFile = null;
    20         if(args!=null && args.length==2)
    21         {
    22             mainJar = args[0];
    23             classDenpdencyFile = args[1];
    24         }
    25         else {
    26             mainJar = "F:Program FilesJavajre7librt.jar";
    27             classDenpdencyFile = "F:Program FilesJavajre7libclassdepency.txt";
    28         }
    29         ListdepencyClass = new ArrayList();
    30         BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(classDenpdencyFile)));
    31         String templine = br.readLine();
    32         // load all the dependency class and store them in a array list;
    33         while(templine!=null) {
    34             int end = templine.lastIndexOf("from");
    35             int begin = templine.lastIndexOf("[Loaded")+7;
    36             String className = templine.substring(begin,end).replace(".", "/").trim();
    37             depencyClass.add(className);
    38             templine= br.readLine();
    39         }
    40         JarFile zipIn = new JarFile(mainJar);
    41         InputStream readin = null;
    42         JarOutputStream jos = new JarOutputStream(new FileOutputStream("rt.jar"));
    43         JarInputStream  jis = new JarInputStream(new FileInputStream(mainJar));
    44         JarEntry entry = jis.getNextJarEntry();
    45         while(entry!=null) {
    46             String name = entry.getName();
    47             //remove the .class suffix.
    48             name = name.substring(0,name.lastIndexOf("."));
    49             if(depencyClass.contains(name)) {
    50                 //put an entry record and write the binary data
    51                 jos.putNextEntry(entry);
    52                 readin = zipIn.getInputStream(entry);
    53                 byte[] temp = new byte[4096];
    54                 int count = readin.read(temp);
    55                 while (count != -1) {
    56                         jos.write(temp, 0, count);
    57                         count = readin.read(temp);
    58                 }
    59                 readin.close();
    60             }
    61             entry = jis.getNextJarEntry();
    62         }
    63         jis.close();
    64         jos.close();
    65     }
    66 }
    1 运行下面Java命令,来生产简化版的rt.jar
    1 java test.ReduceJRE  "F:Program FilesJavajre7lib t.jar"  "F:Program FilesJavajre7libclassdepency.txt"

    会在当前目录下生产一个精简版的rt.jar,用这个简化的rt.jar替代原来的rt.jar, 然后绑定JRE和桌程序一起发布。


    这里有个需要主意的事项就是内部类的class文件是否需要特殊处理, 结论是不需要特殊处理. 

    因为我们做了完全的回归测试,用到的所有类(包括内部类),都已经加装了。

    如果发现一个类有多个内部类而classdepenency.txt里面却显示只有一个内部类被加装,那是因为非静态内部类,只有在用到的情况下,才会加装。

    既然我们的回归测试时都没有用到它,那么就说明是不需要的,因此内部类也不需要特殊考虑.



    2.这里给出一个gc输出,要求给出一个你认为最可能的启动JVM参数,并说明为什么?


    Heap
     def new generation   total 6464K, used 115K [0x34e80000, 0x35580000, 0x35580000)
      eden space 5760K,   2% used [0x34e80000, 0x34e9cd38, 0x35420000)
      from space 704K,   0% used [0x354d0000, 0x354d0000, 0x35580000)
      to   space 704K,   0% used [0x35420000, 0x35420000, 0x354d0000)
     tenured generation   total 18124K, used 8277K [0x35580000, 0x36733000, 0x37680000)
       the space 18124K,  45% used [0x35580000, 0x35d95758, 0x35d95800, 0x36733000)
     compacting perm gen  total 16384K, used 16383K [0x37680000, 0x38680000, 0x38680000)
       the space 16384K,  99% used [0x37680000, 0x3867ffc0, 0x38680000, 0x38680000)
        ro space 10240K,  44% used [0x38680000, 0x38af73f0, 0x38af7400, 0x39080000)
        rw space 12288K,  52% used [0x39080000, 0x396cdd28, 0x396cde00, 0x39c80000)


    首先,这是一个client JVM生产的heap信息,因为加入-Server后得到的分代的标识都和例子很不一样.
    但是对于很多非服务器的桌面系统默认运行的时候都是-client,所以不能确定是否指定了-client,只知道是运行在client JVM中.

    对于Tenured Generation    当前大小=0x36733000-0x35580000=18124K=17.69921875M   总大小=0x37680000-0x35580000=33M
    对于def new generation    新生代的内存总是一次性申请完的, 所以当前大小总是和总大小相等的,总大小=0x35580000-0x34e80000=7M   

    新生代:老年代=7:33 不是一个能够使用-XX:NewRatio来按比例分配的结果.

    JVM 默认的比例是 新生代:老年代=1:2, 也和样例不符合,所以也不是默认值.

    推测是加入了-Xmn7M来控制新生代,因此堆的最大值就是-Xmx40M。


    对于老年代:初始大小=0x35d95758-0x35580000=8M,所以-Xms=15M

    在新生代内部 s0:s1:eden=1:1:8 符合-XX:SurvivorRatio=8的分配结果,但是这个也是新生代内部默认的分配比例,所以不能确定是否指定了-XX:SurvivorRatio=8

    对于Perm gen , 总大小=0x38680000-0x37680000=16M,初始大小=0x3867ffc0-0x37680000=15M


    样例是GC的详细信息,所以肯定使用了 -XX:+PrintGCDetails


    总结如下: 方括号里的参数是不确定的,可有可无.

    -XX:+PrintGCDetails  -XX:MaxPermSize=16M  -XX:PermSize=15M -Xmx40M -Xms15M -Xmn7m  [-XX:SurvivorRatio=8]  [-client]

  • 相关阅读:
    C# 设计模式
    FutureTask、Fork/Join、 BlockingQueue
    线程的几种创建方式
    行锁、表锁、乐观锁、悲观锁
    J.U.C之AQS
    同步容器并发容器
    线程不安全类
    线程封闭
    不可变对象
    安全发布对象—单例模式
  • 原文地址:https://www.cnblogs.com/princessd8251/p/3935388.html
Copyright © 2011-2022 走看看