JAVA的内存分配机制,在很多地方都已经解析很多次了,个人如何方便的来直观的了解,还有很多人不是很清楚,或者没有这样的机会,在这里我结合一个小例子,采用JDK自带的JConsole来说一下JVM的内存分配机制。
案例
首先解释下场景,服务端是一个通信服务器,接受客户端发过来的通信信息,并做业务处理;服务端采用JAVA中的MINA2框架,客户端可以任意,C++也好,JAVA也好,只要符合服务端规定的消息结构,发给通信服务器都能处理。
为了让大家更清楚,可以用MINA2框架中的时间服务器的例子来稍作修改模拟这个场景。系统环境,APACHE MINA2.0.4 + JDK1.6 + Eclipse3.7。
服务端代码如下:
Java代码 收藏代码
public class MinaTimeServer {
/** We will use a port above 1024 to be able to launch the server with a standard user */
private static final int PORT = 9123;
/**
* The server implementation. It's based on TCP, and uses a logging filter
* plus a text line decoder.
*/
public static void main(String[] args) throws IOException {
// Create the acceptor
IoAcceptor acceptor = new NioSocketAcceptor();
// Add two filters : a logger and a codec
acceptor.getFilterChain().addLast( "logger", new LoggingFilter() );
acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" ))));
//acceptor.getFilterChain().addLast("exector", new ExecutorFilter(Executors.newCachedThreadPool()));
acceptor.getFilterChain().addLast("exector", new ExecutorFilter());
// Attach the business logic to the server
acceptor.setHandler( new TimeServerHandler() );
// Configurate the buffer size and the iddle time
acceptor.getSessionConfig().setReadBufferSize( 2048 );
acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, 10 );
// And bind !
acceptor.bind( new InetSocketAddress(PORT) );
}
}
业务处理器(这里当作一个时间服务器,接受到信息之后就立刻返回服务器当前时间)
Java代码 收藏代码
public class TimeServerHandler extends IoHandlerAdapter
{
/**
* Trap exceptions.
*/
@Override
public void exceptionCaught( IoSession session, Throwable cause ) throws Exception
{
cause.printStackTrace();
}
/**
* If the message is 'quit', we exit by closing the session. Otherwise,
* we return the current date.
*/
@Override
public void messageReceived( IoSession session, Object message ) throws Exception
{
String str = message.toString();
if( str.trim().equalsIgnoreCase("quit") ) {
// "Quit" ? let's get out ...
session.close(true);
return;
}
// Send the current date back to the client
Date date = new Date();
session.write( date.getTime());
System.out.println("Message written...");
}
/**
* On idle, we just write a message on the console
*/
@Override
public void sessionIdle( IoSession session, IdleStatus status ) throws Exception
{
System.out.println( "IDLE " + session.getIdleCount( status ));
}
}
客户端JAVA代码:
Java代码 收藏代码
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
public class MinaTimeClient {
public void mutiSendMsg() {
// 创建客户端连接器.
NioSocketConnector connector = new NioSocketConnector();
connector.getFilterChain().addLast("logger", new LoggingFilter());
connector.getFilterChain().addLast(
"codec",
new ProtocolCodecFilter(new TextLineCodecFactory(Charset
.forName("UTF-8")))); // 设置编码过滤器
connector.setConnectTimeoutMillis(30000);
connector.setHandler(new TimeClientHandler());// 设置事件处理器
ConnectFuture cf = connector.connect(new InetSocketAddress("127.0.0.1",
9908));// 建立连接
cf.awaitUninterruptibly();// 等待连接创建完成
cf.getSession().write("hello");// 发送消息
cf.getSession().write("quit");// 发送消息
cf.getSession().getCloseFuture().awaitUninterruptibly();// 等待连接断开
connector.dispose();
}
public static void main(String[] args) {
/*
MinaTimeClient client = new MinaTimeClient();
for(int i = 0; i < 1000; i ++) {
client.mutiSendMsg();
}*/
//int size = keywordMap.size();
long startTime = System.currentTimeMillis();
int thread_num = 100;
int client_num = 2000;
// TODO Auto-generated method stub
ExecutorService exec = Executors.newCachedThreadPool();
// 50个线程可以同时访问
final Semaphore semp = new Semaphore(thread_num);
final CountDownLatch countDownLatch = new CountDownLatch(client_num);
List<Thread> list = new ArrayList<Thread>();
// 模拟2000个客户端访问
for (int index = 0; index < client_num; index++) {
final int NO = index;
Thread run = new Thread() {
public void run() {
while(true){
try {
// 获取许可
//semp.acquire();
new MinaTimeClient().mutiSendMsg();
// System.out.println(result);
// Thread.sleep((long) (Math.random()) * 1000);
// 释放
System.out.println("第:" + NO + " 个");
// semp.release();
Thread.sleep(500);
//countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
list.add(run);
//exec.execute(run);
}
for (Thread thread : list) {
thread.start();
}
//try {
//countDownLatch.await();
System.out.println("end time::::" + (System.currentTimeMillis() - startTime));
// 退出线程池
// exec.shutdown();
//} catch (InterruptedException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
//}
}
}
客户端处理类:
Java代码 收藏代码
public class TimeClientHandler extends IoHandlerAdapter {
public TimeClientHandler() {
}
@Override
public void messageReceived(IoSession session, Object message)
throws Exception {
System.out.println(message);// 显示接收到的消息
}
}
代码准备好之后,启动通信服务器服务端,然后启动客户端;
然后在打开你的jconsole界面,选择需要观察的那个服务端的JAVA进程;
首页就是类似这样的一个界面(注意:这篇文章里面所有的截图都是在模拟程序运行5个小时以后截下来的):
|
|