V8引擎常用命令

1、测试文件test.js

function log(msg){
    console.log(msg)
}

hi = "hello"
log(hi)

2、输出AST语法树

d8 --print-ast test.js
[generating bytecode for function: ]
--- AST ---
FUNC at 0
. KIND 0
. LITERAL ID 0
. SUSPEND COUNT 0
. NAME ""
. INFERRED NAME ""
. DECLS
. . FUNCTION "log" = function log
. EXPRESSION STATEMENT at 47
. . ASSIGN at 50
. . . VAR PROXY unallocated (0000022CC5A21D98) (mode = DYNAMIC_GLOBAL, assigned = true) "hi"
. . . LITERAL "hello"
. EXPRESSION STATEMENT at 61
. . ASSIGN at -1
. . . VAR PROXY local[0] (0000022CC5A21CC8) (mode = TEMPORARY, assigned = true) ".result"
. . . CALL
. . . . VAR PROXY unallocated (0000022CC5A21B10) (mode = VAR, assigned = true) "log"
. . . . VAR PROXY unallocated (0000022CC5A21D98) (mode = DYNAMIC_GLOBAL, assigned = true) "hi"
. RETURN at -1
. . VAR PROXY local[0] (0000022CC5A21CC8) (mode = TEMPORARY, assigned = true) ".result"

[generating bytecode for function: log]
--- AST ---
FUNC at 12
. KIND 0
. LITERAL ID 1
. SUSPEND COUNT 0
. NAME "log"
. PARAMS
. . VAR (0000022CC5A21B68) (mode = VAR, assigned = false) "msg"
. DECLS
. . VARIABLE (0000022CC5A21B68) (mode = VAR, assigned = false) "msg"
. EXPRESSION STATEMENT at 24
. . CALL
. . . PROPERTY at 32
. . . . VAR PROXY unallocated (0000022CC5A21D18) (mode = DYNAMIC_GLOBAL, assigned = false) "console"
. . . . NAME log
. . . VAR PROXY parameter[0] (0000022CC5A21B68) (mode = VAR, assigned = false) "msg"

hello

3、输出作用域

d8 --print-scopes test.js
Inner function scope:
function log () { // (000001E067B50EA8) (12, 43)
  // 2 heap slots
  // local vars:
  VAR msg;  // (000001E067B54E18) never assigned
}
Global scope:
global { // (000001E067B50C88) (0, 68)
  // will be compiled
  // 1 stack slots
  // temporary vars:
  TEMPORARY .result;  // (000001E067B51288) local[0]
  // local vars:
  VAR log;  // (000001E067B510D0)
  // dynamic vars:
  DYNAMIC_GLOBAL hi;  // (000001E067B51358)

  function log () { // (000001E067B50EA8) (12, 43)
    // lazily parsed
    // 2 heap slots
  }
}
Global scope:
function log (msg) { // (000001E067B50EA8) (12, 43)
  // will be compiled
  // local vars:
  VAR msg;  // (000001E067B51128) parameter[0], never assigned
}
hello

4、输出字节码

d8 --print-bytecode test.js
[generated bytecode for function:  (0x03970824fc39 <SharedFunctionInfo>)]
Parameter count 1
Register count 3
Frame size 24
         000003970824FCEA @    0 : 12 00             LdaConstant [0]
         000003970824FCEC @    2 : 26 fa             Star r1
         000003970824FCEE @    4 : 27 fe f9          Mov <closure>, r2
         000003970824FCF1 @    7 : 61 37 01 fa 02    CallRuntime [DeclareGlobals], r1-r2
         000003970824FCF6 @   12 : 12 01             LdaConstant [1]
         000003970824FCF8 @   14 : 15 02 00          StaGlobal [2], [0]
         000003970824FCFB @   17 : 13 03 02          LdaGlobal [3], [2]
         000003970824FCFE @   20 : 26 fa             Star r1
         000003970824FD00 @   22 : 13 02 04          LdaGlobal [2], [4]
         000003970824FD03 @   25 : 26 f9             Star r2
         000003970824FD05 @   27 : 5d fa f9 06       CallUndefinedReceiver1 r1, r2, [6]
         000003970824FD09 @   31 : 26 fb             Star r0
         000003970824FD0B @   33 : aa                Return
Constant pool (size = 4)
000003970824FCB1: [FixedArray] in OldSpace
 - map: 0x0397080404b1 <Map>
 - length: 4
           0: 0x03970824fc61 <FixedArray[2]>
           1: 0x03970824fc01 <String[#5]: hello>
           2: 0x03970824fbf1 <String[#2]: hi>
           3: 0x0397081c692d <String[#3]: log>
Handler Table (size = 0)
Source Position Table (size = 0)
[generated bytecode for function: log (0x03970824fc71 <SharedFunctionInfo log>)]
Parameter count 2
Register count 2
Frame size 16
         000003970824FE4E @    0 : 13 00 00          LdaGlobal [0], [0]
         000003970824FE51 @    3 : 26 fa             Star r1
         000003970824FE53 @    5 : 28 fa 01 02       LdaNamedProperty r1, [1], [2]
         000003970824FE57 @    9 : 26 fb             Star r0
         000003970824FE59 @   11 : 59 fb fa 02 04    CallProperty1 r0, r1, a0, [4]
         000003970824FE5E @   16 : 0d                LdaUndefined
         000003970824FE5F @   17 : aa                Return
Constant pool (size = 2)
000003970824FE1D: [FixedArray] in OldSpace
 - map: 0x0397080404b1 <Map>
 - length: 2
           0: 0x0397081c68b9 <String[#7]: console>
           1: 0x0397081c692d <String[#3]: log>
Handler Table (size = 0)
Source Position Table (size = 0)
hello

5、测试文件test1.js

let a = {x:1}

function bar(obj) { 
  return obj.x 
}

function foo (count) { 
  let ret = 0
  for(let i = 1; i < count; i++) {
    ret += bar(a)
  }
  return ret
}

//foo(7049)
//foo(100000)

6、输出优化信息

//foo(7049)
d8 --trace-opt-verbose test1.js
[not yet optimizing foo, not enough ticks: 0/2 and ICs changed]

//foo(10000)
[not yet optimizing foo, not enough ticks: 0/2 and ICs changed]
[marking 0x01410824fe35 <JSFunction foo (sfi = 000001410824FCD9)> for optimized recompilation, reason: small function]
[compiling method 0x01410824fe35 <JSFunction foo (sfi = 000001410824FCD9)> using TurboFan OSR]
[optimizing 0x01410824fe35 <JSFunction foo (sfi = 000001410824FCD9)> - took 141.370, 62.753, 1.551 ms]

7、输出反优化信息

//没有输出。。。
d8 --trace-deopt test1.js

8、test2.js

function strToArray(str) {
  let i = 0
  const len = str.length
  let arr = new Uint16Array(str.length)
  for (; i < len; ++i) {
    arr[i] = str.charCodeAt(i)
  }
  return arr;
}

function foo() {
  let i = 0
  let str = 'test V8 GC'
  while (i++ < 1e5) {
    strToArray(str);
  }
}

foo()

9、输出反优化信息

d8 --trace-gc test2.js
[4600:0000019D00000000]      490 ms: Scavenge 1.2 (2.4) -> 0.3 (3.4) MB, 14.5 / 0.0 ms  (average mu = 1.000, current mu = 1.000) allocation failure
[4600:0000019D00000000]      500 ms: Scavenge 1.2 (3.4) -> 0.3 (3.6) MB, 2.0 / 0.0 ms  (average mu = 1.000, current mu = 1.000) allocation failure
[4600:0000019D00000000]      501 ms: Scavenge 1.3 (3.6) -> 0.3 (3.6) MB, 0.1 / 0.0 ms  (average mu = 1.000, current mu = 1.000) allocation failure
[4600:0000019D00000000]      503 ms: Scavenge 1.3 (3.6) -> 0.3 (3.6) MB, 0.1 / 0.0 ms  (average mu = 1.000, current mu = 1.000) allocation failure
[4600:0000019D00000000]      505 ms: Scavenge 1.3 (3.6) -> 0.3 (3.6) MB, 0.1 / 0.0 ms  (average mu = 1.000, current mu = 1.000) allocation failure
[4600:0000019D00000000]      506 ms: Scavenge 1.3 (3.6) -> 0.3 (3.6) MB, 0.1 / 0.0 ms  (average mu = 1.000, current mu = 1.000) allocation failure
[4600:0000019D00000000]      508 ms: Scavenge 1.3 (3.6) -> 0.3 (3.6) MB, 0.1 / 0.0 ms  (average mu = 1.000, current mu = 1.000) allocation failure
[4600:0000019D00000000]      509 ms: Scavenge 1.3 (3.6) -> 0.3 (3.6) MB, 0.1 / 0.0 ms  (average mu = 1.000, current mu = 1.000) allocation failure
[4600:0000019D00000000]      511 ms: Scavenge 1.3 (3.6) -> 0.3 (3.6) MB, 0.1 / 0.0 ms  (average mu = 1.000, current mu = 1.000) allocation failure
[4600:0000019D00000000]      513 ms: Scavenge 1.3 (3.6) -> 0.3 (3.6) MB, 0.1 / 0.0 ms  (average mu = 1.000, current mu = 1.000) allocation failure
[4600:0000019D00000000]      515 ms: Scavenge 1.3 (3.6) -> 0.3 (3.6) MB, 0.1 / 0.0 ms  (average mu = 1.000, current mu = 1.000) allocation failure
[4600:0000019D00000000]      516 ms: Scavenge 1.3 (3.6) -> 0.3 (3.6) MB, 0.1 / 0.0 ms  (average mu = 1.000, current mu = 1.000) allocation failure
[4600:0000019D00000000]      518 ms: Scavenge 1.3 (3.6) -> 0.3 (3.6) MB, 0.1 / 0.0 ms  (average mu = 1.000, current mu = 1.000) allocation failure
[4600:0000019D00000000]      520 ms: Scavenge 1.3 (3.6) -> 0.3 (3.6) MB, 0.1 / 0.0 ms  (average mu = 1.000, current mu = 1.000) allocation failure

10、test3.js

function Foo(property_num,element_num) {
  //添加可索引属性
  for (let i = 0; i < element_num; i++) {
      this[i] = `element${i}`
  }
  //添加常规属性
  for (let i = 0; i < property_num; i++) {
      let ppt = `property${i}`
      this[ppt] = ppt
  }
}
var bar = new Foo(10,10)
console.log(%HasFastProperties(bar));
delete bar.property2
console.log(%HasFastProperties(bar));

11、使用内部方法

//%HasFastProperties测试是否有快属性
d8 --allow-natives-syntax test3.js
true
false

编译V8引擎

1、安装Visual Studio 2017

2、从微软下载Windows 10 SDK,安装“Debugging Tools for Windows”

https://developer.microsoft.com/en-US/windows/downloads/windows-10-sdk/

3、设置代理

# git的http代理设置
git config --global http.proxy 127.0.0.1:9528
git config --global https.proxy 127.0.0.1:9528

# 可以通过操作系统设置http代理
# 也可以通过通过命令行设置http代理设置(管理员权限)
netsh winhttp set proxy 127.0.0.1:9528

# 设置cipd_client的http代理设置
set HTTP_PROXY=127.0.0.1:9528
set HTTPS_PROXY=127.0.0.1:9528

4、环境变量

# 启动 VS2017 x86_amd64 命令行环境
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsx86_amd64.bat"

# 环境变量
set PATH=D:\GitGoogleV8\depot_tools_win;D:\NeoLang\Python\Python37;%PATH%
set DEPOT_TOOLS_WIN_TOOLCHAIN=0

5、下载源码

mkdir V8Build
cd V8Build
# V8Build
fetch v8

cd v8
# V8Build/v8
git pull origin 8.3.82
cd ..

6、同步环境

# V8Build
gclient sync

7、生成解决方案

cd v8/src
# V8Build/v8/src
gn gen --ide=vs out\Default
# 也可以设置filters,如果是看chrome源码,最好设置一下,因为有几千个项目
# gn gen --ide=vs --filters=//chrome --no-deps out\Default

8、编译

# 用vs打开sln,并编译
# 编译过程中,有时会出现文件无法访问等情况
# 可以在命令行中执行,然后用VS继续编译就可以成功了
# V8Build/v8/src
devenv out\Default\all.sln

9、测试

# V8Build/v8/src
cd out\Default
# V8Build/v8/src/out/Default
v8_shell.exe

JSP输出容器的JVM参数

<%@ page language="java" import="java.util.*, java.lang.management.*" pageEncoding="UTF-8"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>系统参数输出</title>
<style type="text/css">
table
{
    border-collapse:collapse;
}
td
{
    border:1px solid #427BD6;
}
</style>
</head>

<body style="background-color:#f2f2f2;">

<h1>环境变量</h1>
<table>
<%
    Map<String, String> map = System.getenv();
    //RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
    //Map<String, String> map = runtimeMxBean.getSystemProperties();
    for(String key : map.keySet())
    {
        out.println("<tr>");
        out.println("<td>");
        out.println(key);
        out.println("</td>");
        out.println("<td>");
        out.println(map.get(key));
        out.println("</td>");
        out.println("</tr>");
    }     
%>
</table>

<h1>JVM参数</h1>
<table>
<% 
    RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
    
    out.println("<tr>");
    out.println("<td>");
    out.println(runtimeMxBean.getVmVendor()+" || "+runtimeMxBean.getVmName() +" || "+ runtimeMxBean.getVmVersion());
    out.println("</td>");
    out.println("</tr>");
    
    out.println("<tr>");
    out.println("<td>");
    out.println(runtimeMxBean.getSpecVendor()+" || "+runtimeMxBean.getSpecName() +" || "+ runtimeMxBean.getSpecVersion());
    out.println("</td>");
    out.println("</tr>");
    
    out.println("<tr>");
    out.println("<td>");
    out.println(runtimeMxBean.getName()+" || "+runtimeMxBean.getStartTime() +" || "+ runtimeMxBean.getUptime());
    out.println("</td>");
    out.println("</tr>");
    
    out.println("<tr>");
    out.println("<td>");
    out.println("MaxMemory="+Runtime.getRuntime().maxMemory()/1024/1024 + "m ");
    out.println("TotalMemory="+Runtime.getRuntime().totalMemory()/1024/1024 + "m ");
    out.println("FreeMemory="+Runtime.getRuntime().freeMemory()/1024/1024 + "m ");
    out.println("</td>");
    out.println("</tr>");
    
    List<MemoryPoolMXBean> memoryPoolMXBeans = ManagementFactory.getMemoryPoolMXBeans();
    for (MemoryPoolMXBean bean : memoryPoolMXBeans)
    {
        out.println("<tr>");
        out.println("<td>");
        out.println(bean.getName()+" || "+bean.getType()+" || Init="+bean.getUsage().getInit()/1024/1024+
        "m Max="+bean.getUsage().getMax()/1024/1024+"m Used="+bean.getUsage().getUsed()/1024/1024+
        "m Committed="+bean.getUsage().getCommitted()/1024/1024+"m ");
        out.println("</td>");
        out.println("</tr>");
    }
    
    List<String> arguments = runtimeMxBean.getInputArguments();
    for(String arg:arguments)
    {
        out.println("<tr>");
        out.println("<td>");
        out.println(arg);
        out.println("</td>");
        out.println("</tr>");
    }
%>
</table>

<h1>系统参数</h1>
<table>
<%
    Properties props = System.getProperties();
    for(Object o:props.keySet())
    {
        out.println("<tr>");
        out.println("<td>");
        out.println(o);
        out.println("</td>");
        out.println("<td>");
        out.println(props.get(o));
        out.println("</td>");
        out.println("</tr>");
    }
%>
</table>
</body>
</html>

Java四种引用方式

最近写了个例子,说明了一下强引用、软引用、弱引用、虚引用的区别。

1、NString.java

package com.neohope.reference;

/**
 * Created by Hansen
 */
public class NString {
    private String name;
    private String value;

    public NString(String name, String value)
    {
        this.name = name;
        this.value=value;
    }

    public NString(String name, StringBuilder builder)
    {
        this.name = name;
        this.value=builder.toString();
    }

    public String Name()
    {
        return name;
    }

    public String Value()
    {
        return value;
    }

    @Override
    protected void finalize()
    {
        System.out.println(">> "+Name()+" finalize called");
        try {
            super.finalize();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
}

2、TestReferenceA.java

package com.neohope.reference;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.WeakHashMap;

/**
 * Created by Hansen
 * JVM参数:
 * -XX:+PrintGCDetails
 * -Xms6m -Xmx12m
 */
public class TestReferenceA {
    public static void main(String[] args) {
        //申请内存
        Runtime rt=Runtime.getRuntime();
        System.out.println("Total memory is "+rt.totalMemory());
        int MemSize = 1024*1024*1;
        StringBuilder builder = new StringBuilder(MemSize);
        for (int i=0;i<MemSize/8;i++) {
            builder.append("ABCDEFGH");
        }
        System.out.println("Total memory is "+rt.totalMemory());

        //用s00与s01两个大字符串演示强引用与软引用的区别
        NString s00 = new NString("s00",builder);
        NString s01 = new NString("s01",builder);
        //s02与s03演示WeakReference的两种用法
        NString s02 = new NString("s02","s03");
        String key03 = new String("k03");
        NString s03 = new NString("s03","s03");
        //s04演示PhantomReference
        NString s04 = new NString("s04","s04");
        System.out.println("Total memory is "+rt.totalMemory());

        //第1类、强引用的对象,也最常用到的类型,内存不足时JVM将抛出异常也不要释放这些内存
        NString strongRef = s00;
        //第2类、只有软引用的数据,内存不足时JVM会回收这些内存
        SoftReference<NString> softRef = new SoftReference<NString>(s01);
        //第3类、只有弱引用的数据,无论内存是否充足JVM会回收这些内存,也就是弱引用不会影响对象的生命周期
        WeakReference<NString> weakRef = new WeakReference<NString>(s02);
        //WeakHashMap很有用,当key022为null时,s022也就会被GC咯
        WeakHashMap weakHashMap = new WeakHashMap();
        weakHashMap.put(key03,s03);
        //第4类、只有虚引用的数据,一开始refQueue为空,被GC才会有值
        ReferenceQueue refQueue = new ReferenceQueue<String>();
        PhantomReference<NString> phantomRef = new PhantomReference<NString>(s04, refQueue);

        //有强引用时,输出初始化情况
        System.out.println("With strong ref strongRef is " + (strongRef==null?"null":"not null"));
        System.out.println("With strong ref softRef is " + (softRef.get()==null?"null":"not null"));
        System.out.println("With strong ref weakRef is " + (weakRef.get()==null?"null":"not null"));
        System.out.println("With strong ref weakHashMap is " + (weakHashMap.isEmpty() ?"empty":"not empty"));
        //这里为null,当对象被GC时,会得到虚引用对象
        System.out.println("With strong ref refQueue has " + refQueue.poll());
        System.out.println();

        //去掉初始的强引用
        s00 = null;
        s01 = null;
        s02 = null;
        s03 = null;
        s04 = null;

        //多数情况下,没有来得及GC
        System.out.println("Before gc strongRef is " + (strongRef==null?"null":"not null"));
        System.out.println("Before gc softRef is " + (softRef.get()==null?"null":"not null"));
        System.out.println("Before gc weakRef is " + (weakRef.get()==null?"null":"not null"));
        System.out.println("Before gc weakHashMap is " + (weakHashMap.isEmpty() ?"empty":"not empty"));
        //null,当对象被GC时,会得到虚引用对象
        System.out.println("Before gc refQueue has " + refQueue.poll());
        System.out.println();

        //强制GC
        System.gc();
        System.out.println("After first gc strongRef is " + (strongRef==null?"null":"not null"));
        System.out.println("After first gc softRef is " + (softRef.get()==null?"null":"not null"));
        //null,weakRef已经被释放了
        System.out.println("After first gc weakRef is " + (weakRef.get()==null?"null":"not null"));
        System.out.println("After first gc weakHashMap is " + (weakHashMap.isEmpty() ?"empty":"not empty"));
        //与运行环境及GC方法有关,会出现一次有值的情况,然后一直为null
        System.out.println("After first gc refQueue has " + refQueue.poll());
        System.out.println();

        //将key03设为null,强制GC
        key03 = null;
        System.gc();
        System.out.println("After second gc strongRef is " + (strongRef==null?"null":"not null"));
        System.out.println("After second gc softRef is " + (softRef.get()==null?"null":"not null"));
        //null
        System.out.println("After second gc weakRef is " + (weakRef.get()==null?"null":"not null"));
        //empty,由于key被设为空,则会释放掉弱引用对象了
        System.out.println("After second gc weakHashMap is " + (weakHashMap.isEmpty() ?"empty":"not empty"));
        //与运行环境及GC方法有关,会出现一次有值的情况,然后一直为null
        System.out.println("After second gc refQueue has " + refQueue.poll());
        System.out.println();

        //Finalization
        System.runFinalization();
        System.out.println("After Finalization strongRef is " + (strongRef==null?"null":"not null"));
        System.out.println("After Finalization softRef is " + (softRef.get()==null?"null":"not null"));
        //null
        System.out.println("After Finalization weakRef is " + (weakRef.get()==null?"null":"not null"));
        //empty
        System.out.println("After Finalization weakHashMap is " + (weakHashMap.isEmpty() ?"empty":"not empty"));
        //与运行环境及GC方法有关,会出现一次有值的情况,然后一直为null
        System.out.println("After Finalization refQueue has " + refQueue.poll());
        System.out.println();

        //申请内存,造成内存不足
        System.out.println("Total memory is "+rt.totalMemory());
        StringBuilder builder2 = new StringBuilder(MemSize);
        for (int i=0;i<MemSize/8;i++) {
            builder2.append("ABCDEFGH");
        }
        NString tmp0 = new NString("tmp0", builder2);
        System.out.println("Total memory is "+rt.totalMemory());

        System.out.println("When mem is low strongRef is " + (strongRef==null?"null":"not null"));
        //null,内存不足时软引用会被释放
        System.out.println("When mem is low softRef is " + (softRef.get()==null?"null":"not null"));
        //null
        System.out.println("When mem is low weakRef is " + (weakRef.get()==null?"null":"not null"));
        //empty
        System.out.println("When mem is low weakHashMap is " + (weakHashMap.isEmpty() ?"empty":"not empty"));
        //与运行环境及GC方法有关,会出现一次有值的情况,然后一直为null
        System.out.println("When mem is low refQueue has " + refQueue.poll());
        System.out.println();

        //再次申请内存,JMV会内存爆掉
        NString tmp1 = null;
        try
        {
            tmp1 = new NString("tmp1",builder2);
        }
        catch(OutOfMemoryError ex)
        {
            System.out.println("Not enough memory");
        }

        //null
        System.out.println("tmp1 is " + (tmp1==null?"null":"not null"));
        //就算是抛出OutOfMemoryError,仍然不会释放
        System.out.println("When not enough memory strongRef is " + (strongRef==null?"null":"not null"));
        //null
        System.out.println("When not enough memory softRef is " + (softRef.get()==null?"null":"not null"));
        //null
        System.out.println("When not enough memory weakRef is " + (weakRef.get()==null?"null":"not null"));
        //empty
        System.out.println("When not enough memory weakHashMap is " + (weakHashMap.isEmpty() ?"empty":"not empty"));
        //null
        System.out.println("When not enough memory refQueue has " + refQueue.poll());
        System.out.println();
    }
}

3、输出

Total memory is 6094848
Total memory is 6094848
Total memory is 11390976
With strong ref strongRef is not null
With strong ref softRef is not null
With strong ref weakRef is not null
With strong ref weakHashMap is not empty
With strong ref refQueue has null

Before gc strongRef is not null
Before gc softRef is not null
Before gc weakRef is not null
Before gc weakHashMap is not empty
Before gc refQueue has null

After first gc strongRef is not null
After first gc softRef is not null
After first gc weakRef is null
After first gc weakHashMap is not empty
>> s04 finalize called
After first gc refQueue has null
>> s02 finalize called

After second gc strongRef is not null
After second gc softRef is not null
After second gc weakRef is null
After second gc weakHashMap is not empty
After second gc refQueue has java.lang.ref.PhantomReference@15d63da

After Finalization strongRef is not null
After Finalization softRef is not null
After Finalization weakRef is null
After Finalization weakHashMap is not empty
After Finalization refQueue has null

Total memory is 14221312
Total memory is 14221312
When mem is low strongRef is not null
When mem is low softRef is not null
When mem is low weakRef is null
When mem is low weakHashMap is not empty
When mem is low refQueue has null

>> s01 finalize called
Not enough memory
tmp1 is null
When not enough memory strongRef is not null
When not enough memory softRef is null
When not enough memory weakRef is null
When not enough memory weakHashMap is empty
When not enough memory refQueue has null

Java程序如何加密

今天在想Java程序加密的事情,现在市面上的方法,无非是混淆代码,jar包签名等,瞬间就能被破解掉。

我想到了一个很挫的方法,和PE文件加壳脱壳一样,class文件/jar文件为什么不可以呢?

但这样做的话,是有限制的,就是客户必须使用你自己定制的JVM及容器,否则是无法运行的。

具体方法如下:
1、生成class文件后,按一定规则进行加密处理。偷懒的话,直接对称加密好了。
2、生成jar包的时候,同样按一定规则进行加密处理。偷懒的话,zip的时候,增加一个强壮的密码就好了。
3、下载并编译OpenJDK,在读取jar包内容,和class文件的地方,要进行脱壳处理。按上面的思路,就是解压缩和解密处理。
4、当然,定制部分的dll和exe,需要进行PE加壳处理

当然,上面这种方式的话,和加壳脱壳还是有很大的区别的,就是不能自行解压,并要依赖于JVM甚至容器的定制。

如果要真正实现自解压处理的话,就要多做几步:

具体方法如下:
1、编译生成class文件,按一定规则进行加密处理。偷懒的话,直接对称加密好了。
2、生成jar包的时候,同样按一定规则进行加密处理。偷懒的话,zip的时候,增加一个强壮的密码就好了。
3、将需要的所有jar包,按你喜欢的方法,生成一个jar包列表,并打成一个巨大的资源文件。
4、写一个java引导文件,用于处理运行参数,比如入口程序等。
5、写一个自定义classloader+jni+dll,用于读取巨大的资源文件中的jar包及class文件
6、用普通的jvm启动程序,初始化时用引导文件+自定义classloader
7、引导文件+自定义classloader将需要的文件直接解压到内存中,提供给jvm使用
8、dll部分要进行PE加壳处理

JVM常用参数设置

运行方式设置
-client
-server
两者的区别在JIT的编译比例及GC的方式不同,也可以近似的这样理解:client会启动比较快,GC默认为串行,但JIT编译较少,速度慢一些;server启动慢,GC默认为并行,但JIT编译较多,开始速度慢,但JIT编译后会越来越快。

内存设置
-Xms
设置初始化堆的大小

-Xmx
设置最大堆大小

-Xss 或 -XX:ThreadStackSize
设置每个线程栈大小

-Xmn 或 -XX:NewSize
设置年轻代的内存大小

-XX:MaxNewSize
设置最大年轻代新生代内存大小

-XX:PermSize
设置持久代内存大小

-XX:MaxPermSize
设置最大值持久代内存大小

-XX:NewRatio
设置年轻代与年老代的比值

-XX:SurvivorRatio
设置年轻代中Eden区与Survivor区的大小比值

GC设置
-XX:+DisableExplicitGC
禁用java代码中的System.gc()

-XX:+UseSerialGC
设置串行收集器

-XX:+UseParallelGC 或 -XX:+UseParNewGC
设置年轻代为并行收集器

-XX:ParallelGCThreads
设置并行收集器的线程数

或 -XX:+UseParallelOldGC
设置年老代为并行收集

-XX:+UseConcMarkSweepGC
设置年老代为CMS收集

-XX:MaxGCPauseMillis
一次GC最大的停顿时间

-XX:GCTimeRatio
GC占用CPU时间比例

调试GC
-verbose:gc
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintGCApplicationConcurrentTime
-XX:+PrintGCApplicationStoppedTime
-XX:PrintHeapAtGC

调试加载类
-verbose:class 监视加载的类的情况

调试JNI
-verbose:jni

设置字符集为UTF-8
-Djavax.servlet.request.encoding=utf-8
-Dfile.encoding=utf-8

调试SSL
-Djavax.net.debug=ssl:record
-Djavax.net.debug=ssl:handshake
-Djavax.net.debug=all

内存溢出时抓取JVM快照
-XX:+HeapDumpOnOutOfMemoryError

win7x64+cygwin+vs2010编译64位openjdk6

用VS2010编译OpenJDK6,是一个比OpenJDK7更痛苦的过程。

除了OpenJDK7里需要注意的,还有下面几个:
1、编译器版本不同,所以要自行在Makefile中,增加编译器版本
同样的,还有cp一些dll的命令,需要屏蔽

2、命令冲突
主要是sort和echo

3、Windows版本问题,导致部分define失败,以及部分结构体不存在
从而无法编译通过,主要是

jdk/src/windows/native/sun/windows/awtmsg.h
jdk/src/windows/native/sun/windows/awtMMStub.h
jdk/src/windows/native/java/net/NetworkInterface.h

4、jchar*与LPWCHAR之间的CAST失败,主要存在于

jdk/src/windows/native/sun/windows
jdk/src/windows/native/sun/nio/sun
jdk/src/windows/native/sun/java2d/windows
jdk/src/windows/native/sun/awt/splashscreen

5、设置环境变量的命令行:

@set PATH=C:\Windows\system32;

@call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64
@set VS100COMNTOOLS=C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\Tools

@set ANT_HOME=D:/JavaTools/apache-ant-1.8.1
@set PATH=%PATH%;%ANT_HOME%\bin;

@set FREETYPE_HOME=D:/GnuWin/freetype2.4.10
@set PATH=%PATH%;%FREETYPE_HOME%/bin;
@set ALT_FREETYPE_LIB_PATH=%FREETYPE_HOME%/lib64
@set ALT_FREETYPE_HEADERS_PATH=%FREETYPE_HOME%/include

@set ALT_BOOTDIR=D:/JavaJDK/jdk1.6.0_34
@set ARCH_DATA_MODEL=64
@set ARCH=amd64
@set PLATFORM=windows
@set ALT_DROPS_DIR=D:/DiskF/OpenJDK/openjdk6_VS2010_x64/drops
@set ALT_COMPILER_PATH=C:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/bin/amd64

@set PATH=%PATH%;D:\Cygwin\bin;

@set JAVA_HOME=
@set CLASSPATH=

@color 02
@title OpenJDK6+VS2010+x64

@cmd

win7x64+cygwin+vs2010编译64位openjdk7

建议:
1、这是一个比较折腾的过程,可能的话建议用linux
2、建议用英文系统
3、建议用英文版的vc++
4、请不要用带空格的路径,尤其是不要用带中文的路径,

主要问题有:
1、可执行文件版本不兼容
2、win和linux路径问题
3、字符集问题,鄙视一下corba的注释,根本没考虑其他字符
4、cl的MT和MD要统一
5、不同路径下文件名冲突问题,

准备与编译:
1、安装VS2010、windows sdk7.1、VS2010 sp1,注意sp1和windows sdk的安装顺序
也有说只有VS的Express版本才需要安装windows sdk的,我反正都安装了。
2、安装directx sdk9(Summer 2004)
3、安装cygwin,并按照要求,下载相应组件,
http://www.cygwin.com/
http://hg.openjdk.java.net/jdk7/jdk7/raw-file/tip/README-builds.html
其中make组件太新,需要替换为3.8.1以前的版本
http://www.cmake.org/files/cygwin/make.exe-cygwin1.7
4、下载JDK6u22+,并安装
5、下载ant,并解压
6、下载并编译FreeType2.4
http://sourceforge.net/projects/freetype/files/
x64+MD+Release
7、下载OpenJDK7,并解压
8、新建drops文件夹,下载下面三个文件,并放到dorps文件夹中:
jaxp145_01.zip
jdk7-jaf-2010_08_19.zip
jdk7-jaxws2_2_4-b03-2011_05_27.zip
理论上,ant应该可以自动下载这三个文件,但我这里下不到
手工下载的话,在Makefile里找下面三个关键字就好了:
jaxp_src.bundle.name
jaxws_src.bundle.name
jaf_src.bundle.name

9、准备编译,新建run.bat,按自己的路径进行修改:

rem 这里是为了解决路径冲突问题
@set PATH=C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;

rem 注意,这里我的VS和WindowsSDK有冲突,导致VS100COMNTOOLS路径错误
@call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64
@set VS100COMNTOOLS=C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\Tools

rem ANT配置
@set ANT_HOME=D:/JavaTools/apache-ant-1.8.1
@set PATH=%PATH%;%ANT_HOME%\bin;

rem FreeType配置
@set FREETYPE_HOME=D:/GnuWin/freetype2.4.10
@set PATH=%PATH%;%FREETYPE_HOME%/bin;
@set ALT_FREETYPE_LIB_PATH=%FREETYPE_HOME%/lib64
@set ALT_FREETYPE_HEADERS_PATH=%FREETYPE_HOME%/include

rem Cygwin设置
@set PATH=%PATH%;D:\Cygwin\bin;

rem 这里是OpenJDK的设置啦
@set ALT_BOOTDIR=D:/JavaJDK/jdk1.6.0_34
@set ARCH_DATA_MODEL=64
@set ARCH=amd64
@set PLATFORM=windows
@set ALT_DROPS_DIR=D:/DiskF/OpenJDK/openjdk7_VS2010_x64/drops

rem 这两个变量要置空
@set JAVA_HOME=
@set CLASSPATH=

rem 个人爱好
@color 02
@title OpenJDK+VS2010

@cmd

10、运行run.bat

#测试配置:
make sanity
#没有错误的话:
make

我遇到的问题:
1、主要死到了MT和MD上,这个我修改了Makefile,一定要和FreeType保持一致
2、还有FreeType.dll,我编译的是个大Lib,所以Makefile里拷贝dll的语句要去掉
3、corba的字符集问题,要把Makefile里的ascii去掉,因为生成的注释有中文,显然要出错
4、EXE冲突,我的工具版本很多,估计一般人没这么多问题,最后改了PATH,Find改了名称
比如win的find和cygwin的find,Oracle的zip和cygwin的zip
同样,cygwin和(mingw、GnuSetup、GnuWin)的冲突,也要注意
5、还有一个,就是bat中的路径,除Path外尽量用/,因为linux下,\是转义用的
6、尝试了MinGW,发现不够给力啊