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

如何将JVM弄崩溃

什么是JVM的崩溃呢?
JVM已经无法抛出异常了,你会看到这样的错误

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_STACK_OVERFLOW (0xc00000fd) at pc=0x6d8a99c6, pid=2572, tid=964
#
# JRE version: 6.0_22-b04
# Java VM: Java HotSpot(TM) Client VM (17.1-b03 mixed mode, sharing windows-x86
)
# Problematic frame:
# V  [jvm.dll+0x99c6]
#
# An error report file with more information is saved as:
# D:\E\Projects\Java\Crash\hs_err_pid2572.log
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
#

同时会生成hs_err_pidxxxx.log的日志文件。

怎么把JVM弄崩溃呢?
总结了一下,感觉有三种方法
1是利用编译器及JVM自身特性,导致不可恢复的灾难;
2是利用JDK或JVM的bug;
3是用JNI,让JVM鞭长莫及,无论是sun提供的,还是我们自己写的;

import sun.dc.pr.PathDasher; 
import sun.misc.Unsafe;

//方法1
//我最认可的方法
public static void main(String[] args) {
    Object[] o = null;
    while (true) {
        o = new Object[] { o };
    }
}

//方法2
//JDK1.6u23 以前版本中的bug
public static void main(String[] args) {
    Double.parseDouble("2.2250738585072012e-308");
}

//方法3
//JNI
public static void main(String[] args)
{    
    PathDasher dasher = new PathDasher(null) ;
}

//方法4
//JNI
//java -Xbootclasspath/p:. Crash
private static final Unsafe unsafe = Unsafe.getUnsafe();
public static void crash()
{
    unsafe.putAddress(0, 0);
}

public static void main(String[] args) {
    crash();
}