分类存档: java - 第2页

今天想测试map的读取key的性能,结果遇到无法解答的问题。

代码如下:

如果注释掉test2(),启动test2_1(),则test()消耗的时间大幅减少,不知原因。

import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;

public class Test4 {
	private static Map<Integer, Integer> map1 = new HashMap<Integer, Integer>();
	private static Map<String, String> map2 = new HashMap<String, String>();
	private static Map<String, String> map3 = new IdentityHashMap<String, String>();
	private static String testKey = "helloworld";
	private static long time;
	private static long time2;
	private static Integer a = 1500;

	public static void main(String[] args) {
		map3.put(testKey, testKey);
		for (int m = 1000; m < 1010; m++) {
			map1.put(m, m);
			map2.put("" + m, "" + m);
			map3.put("" + m, "" + m);
		}
		for (int mm = 0; mm < 100; mm++) {
			test1();
			test2();
			// test2_1();
		}
	}

	public static void test1() {
		time = System.nanoTime();
		for (int m = 0; m < 1000000000; m++) {
			map1.get(a);
		}
		time2 = System.nanoTime();
		System.out.println("数字:" + (time2 - time));
	}

	public static void test2() {
		time = System.nanoTime();
		for (int m = 0; m < 1000000000; m++) {
			map2.get("hello");
		}
		time2 = System.nanoTime();
		System.out.println("字符:" + (time2 - time));
	}

	public static void test2_1() {
		time = System.nanoTime();
		for (int m = 0; m < 1000000000; m++) {
			map2.get("hello222222222222222222222222222222222222222222222222222222222222222222222222222222222222222");
		}
		time2 = System.nanoTime();
		System.out.println("字符:" + (time2 - time));
	}

	public static void test3() {
		time = System.nanoTime();
		for (int m = 0; m < 1000000000; m++) {
			map3.get(testKey);
		}
		time2 = System.nanoTime();
		System.out.println("字符3:" + (time2 - time));
	}
}

java visualvm jstatd启动时遇到的一个错误

今天启动jstatd时一直报下面的错误:

root@cvs jstatd]# jstatd -J-Djava.security.policy=/opt/joycube/jstatd/tools.policy
Could not contact registry
Connection refused to host: 192.168.17.12; nested exception is:
        java.net.ConnectException: Connection timed out
java.rmi.ConnectException: Connection refused to host: 192.168.17.12; nested exception is:
        java.net.ConnectException: Connection timed out
        at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:619)
        at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:216)
        at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:202)
        at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:341)
        at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
        at java.rmi.Naming.rebind(Naming.java:177)
        at sun.tools.jstatd.Jstatd.bind(Jstatd.java:57)
        at sun.tools.jstatd.Jstatd.bind(Jstatd.java:66)
        at sun.tools.jstatd.Jstatd.main(Jstatd.java:143)
Caused by: java.net.ConnectException: Connection timed out
        at java.net.PlainSocketImpl.socketConnect(Native Method)
        at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
        at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
        at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
        at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
        at java.net.Socket.connect(Socket.java:579)
        at java.net.Socket.connect(Socket.java:528)
        at java.net.Socket.<init>(Socket.java:425)
        at java.net.Socket.<init>(Socket.java:208)
        at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(RMIDirectSocketFactory.java:40)
        at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(RMIMasterSocketFactory.java:147)
        at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:613)
        ... 8 more

上面提示的ip很奇怪。这台机器的ip应该是10.234.10.12

运行hostname -i,显示为192.168.17.12

这是错误的IP,打开 /etc/hosts,发现里面配置了本机名cvs解析为192.158.17.12,这台机器以前换过ip,修改为10.234.10.12。

ok,jstatd可以正常运行了。

查找服务器一个内存溢出的bug

最近两天晚上以每分钟一次的频率进行热更新,测试这种压力程度是否会引起bug。

早上到公司一看服务器已经死掉了,提示outofmemory,看来应该是有一个内存举出的地方。

服务器直接挂掉,连dump内存都无法成功。

使用jprofiler观察内存中的对象时时变化。

jprofiler中发现classloader没有被释放掉?

google之:

http://zeroturnaround.com/rebellabs/rjc201/

http://frankkieviet.blogspot.com/2006/10/how-to-fix-dreaded-permgen-space.html

http://java.jiderhamn.se/2011/12/11/classloader-leaks-i-how-to-find-classloader-leaks-with-eclipse-memory-analyser-mat/

得知:classloader中会引用所加载类中的静态属性,从而导致classloader内存泄露。

将内存dump出来后,使用clipse Memory Analyser (MAT),查看具体哪里泄露。

直接在eclipse 中查找memory analyser 出来好多个软件。

mat 的update site:http://download.eclipse.org/mat/1.3.1/update-site/

其它的memory analyser软件,有时间再去了解下。

 

判断一个类为虚拟类

Modifier.isAbstract(clazz.getModifiers())

以上方式用来判断是clazz是否为虚拟类。

classloader重新加载资源

app在tomcat中运行,默认使用的是WebappClassLoader。

InputStream inputStream =Thread.currentThread().getContextClassLoader().getResourceAsStream(“xls/” +
xlsName);

inputStream只要加载过一次后,就会被WebappClassLoader缓存起来,如果需要加载新的资源文件,需要修改为以下方式:

// 因为webappclassloader会缓存加载的资源,所以每次手动去打开文件
			// InputStream inputStream =
			// GameInstance.gameClassLoader.getResourceAsStream("xls/" +
			// xlsName);
			URL xlsURL = GameInstance.gameClassLoader.getResource("xls/" + xlsName);
			URLConnection resConn = xlsURL.openConnection();
			resConn.setUseCaches(false);
			InputStream inputStream = resConn.getInputStream();

freemark关闭日志

改为logback后就发现freemark疯狂的输出log。

Logger.selectLoggerLibrary(Logger.LIBRARY_NONE);

classloader java热更新

最近几天一直在实现java的热更新。

本来以为使用classloader很容易搞定,结果走过了好几个坑。

1、classloader中的类不允许重复加载。

如果已经加载过的类,需要先判断 findLoadedClass(name)中是否存在,如果已经存在,不要再次加载。

2、classloader最初放在contextLister中,服务启动时,自动启动,结果发现异常无法补获,只好在action中手动加载来进行调试。

3、classloaderA和classloaderB加载相同的类,也会判断为不相同,因为是由不同的classloader加载的。

4、看起来需要在tomcat中使用自己的类进行加载才可以实现热更新。测试下。现在需要在tomcat设置自己的classloader,同时在加载新类时,不能再重新new classloader.

5、先测试下如何从jar中加载类。

晕死,因为我加一个判断字符串是使用的apache common中的stringutils,结果导致classloader直接死掉,还不抛出异常。看来,如果是context class loader,只使用java jdk中的类库。

6、同一个类在不同的classloader中加载,也无法相互赋值。

这里有两种解决方案:

1)在tomcat中使用custom class loader来加载所需要的所有类。

2)需要加载的类的父类和接口交给context class loader加载。这样就可以共同相同classloader加载的接口,通过不同的classloader来加载具体的实现类及子类。

现在终于使用第二种解决方案解决问题。对 classloader及类加载和热更新了解的更深入了。

同时需要测试下,多次defines类是否能行的通。

 

 

 

 

运行时获得所有的类

1、如果使用spring, 可以使用以下方式获得spring context中的所有的类:

public class GameReflect implements ApplicationContextAware {
	public ApplicationContext applicationContext;

@Override
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		this.applicationContext = applicationContext;
	}
public void getAllClass(){
        applicationContext.getBeansOfType(GameBaseAction.class);
}
}

2、除此之外,也可以从classloader中使用一种hack方式获得所有的类:

package cn.joylab.service;

import java.lang.reflect.Field;
import java.util.Vector;

public class ClassLoaderTest extends GameBaseManagerTestCase {
	@org.junit.Test
	public void test1() {
		try {
			Field f = ClassLoader.class.getDeclaredField("classes");
			f.setAccessible(true);

			ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

			Vector<Class> classes = (Vector<Class>) f.get(classLoader);
			for (Class c : classes) {
				System.out.println(c);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

maven设置代理

maven默认直接访问repo仓库,但国外的仓库太慢了。

这里可以在maven/conf/setting.xml中设置代理,设置一个连接国外网速比较快的代理:

<proxies>

<proxy>
<id>optional</id>
<active>true</active>
<protocol>http</protocol>
<username>proxyuser</username>
<password>proxypass</password>
<host>127.0.0.1</host>
<port>8087</port>
<nonProxyHosts>local.net|some.host.com|192.168.17.12|10.234.10.12</nonProxyHosts>
</proxy>

</proxies>

我这里是使用的goagent,所以就设置为本机的goagent为代理,速度果然提高了好多。

一篇介绍jsr用法的文章

一篇介绍jsr用法的文章:

https://today.java.net/pub/a/today/2008/04/10/source-code-analysis-using-java-6-compiler-apis.html#accessing-the-abstract-syntax-tree-the-compiler-tree-api

jsr可以将java source生成为一个TreePath,可以读取到该类中的所有信息。(除了备注 -.-!)。

可以了,现在转向eclipse adt看看能否获得带备注的ast。