类HashMap,但内存减少到原1/6的实现
时间:2009-10-28 11:08:33来源:网络 作者:未知 点击:429次 
java中的Map在提供方便实用的同时,也存在内存浪费巨大的问题。当Map中的Entry数量达到1000万 条以上的时候,需要数G的内存空间 .这里提到的Map使用形式为HashMap<String,Byte>,平均每个key在20个字符左右,最多不超过200
| java中的Map在提供方便实用的同时,也存在内存浪费巨大的问题。当Map中的Entry数量达到1000万 条以上的时候,需要数G的内存空间 .这里提到的Map使用形式为HashMap<String,Byte>,平均每个key在20个字符左右,最多不超过200字符. 在实际情况下,有差不多5/6的内存浪费 在存放实际数据无关的地方.在一些一次写入多次读去的地方,完全没有必要浪费这么多的资源,下面就通过一个简单的实现说明。 算法说明: 按照key的长度信息将所有的entry放进不同的队列中,为了方便此时的entry队列已经排好序,当然也可以加进内存后再排序. 现在有很多的队列了,在查询的时候根据查询词长度选择一个队列,在队列中通过2分法查找. 算法适用性: 适用于key值集中在一定范围,value为简单类型(byte、int、long、float、double等),数据量在百万条以上,内存匮乏的情况. view plaincopy to clipboardprint?·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
 import java.io.BufferedInputStream;
 import java.io.BufferedReader;
 import java.io.DataInputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileReader;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 public class BSortMap{
 
 private static Map<Integer,BSortMap> bulk = new HashMap<Integer, BSortMap>();
 
 final private byte[] entrys; //entry数组
 private int count = 0;
 final private int keyLength; //key的字节大小
 final private int entryLength; //每一个Entry的字节数
 
 public BSortMap(int capacity, int keyLen){
 this.keyLength = keyLen;
 entryLength = keyLen + 1;
 entrys = new byte[capacity * entryLength];
 }
 
 public int size(){
 return count;
 }
 
 /**
 * 添加记录条目。条目都是已经排好序的。
 * src格式为<key,value>
 * @param src
 */
 final public void add(byte src[]){
 System.arraycopy(src, 0, entrys, count * entryLength, entryLength);
 count++;
 }
 
 final private int compare(final int begin,final byte[] b){
 int i = 0;
 for (; entrys[begin+i] == b[i] && i < b.length - 1; i++)
 ;
 return entrys[begin + i] - b[i];
 }
 
 /**
 * 获取与key关联的value值
 * @param key
 * @return 如果不存在key关联的value则返回-1
 */
 final public byte get(final byte[] key){
 int i = 0;
 int j = count-1;
 int mid;
 while(i<=j){
 mid = (i + j)>>1;
 final int ret =compare(mid*entryLength,key);
 if(ret==0){
 return entrys[mid*entryLength + keyLength]; //返回结果
 } else if (ret < 0){
 i = mid+1;
 }else{
 j = mid -1;
 }
 
 }
 return -1;
 
 }
 
 public static void main(String args[]) throws IOException{
 File dir = new File("D:/workspace/partion_keyword/sort");
 File[] files = dir.listFiles();
 
 for(File f:files){
 
 DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(f)));
 /*
 * f为根据key值已经排好序的文件
 * 文件格式为:
 * entrysCount:  一个整形数字,值为总的记录条目
 * keyLength: 一个整形数字,值为关键字的字节长度
 * <key,value>列表
 */
 final int entrysCount = in.readInt();
 final int keyLength = in.readInt();
 byte[] buffer = new byte[keyLength + 1];
 BSortMap bst = new BSortMap(entrysCount,keyLength);
 int i = 0;
 while(in.available() > 0){
 int l = in.read(buffer);
 while(l != keyLength +1){
 System.err.println("not equal."+l);
 }
 bst.add(buffer);
 i++;
 }
 bulk.put(keyLength,bst);
 if (entrysCount != i)
 System.err.println(f.getName()+":"+entrysCount+","+i);
 in.close();
 }
 
 BufferedReader read = new BufferedReader(new FileReader("D:/eclipse/workspace/conf/wiki_kws.data"));
 String line ;
 int count = 0;
 long start = System.currentTimeMillis();
 while((line = read.readLine())!=null){
 byte key[] = line.trim().getBytes();
 BSortMap bt = bulk.get(key.length);
 if(bt != null && bt.get(key) != -1){
 count++;
 }
 }
 long end = System.currentTimeMillis();
 System.out.println(end - start);
 System.out.println("count:"+count);
 
 int totalcount = 0;
 for(BSortMap s: bulk.values()){
 totalcount += s.size();
 }
 System.out.println("total count:"+totalcount);
 read.close();
 
 /*while(true){
 Scanner in = new Scanner(System.in);
 String key = in.next().trim();
 if(key.equalsIgnoreCase("exit"))
 break;
 int len = key.trim().getBytes().length;
 BSort bt = bulk.get(len);
 byte v = bt.get(key.getBytes());
 System.err.println(key+"="+v);
 }*/
 
 }
 }
 import java.io.BufferedInputStream;
 import java.io.BufferedReader;
 import java.io.DataInputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileReader;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 public class BSortMap{
 
 private static Map<Integer,BSortMap> bulk = new HashMap<Integer, BSortMap>();
 
 final private byte[] entrys; //entry数组
 private int count = 0;
 final private int keyLength; //key的字节大小
 final private int entryLength; //每一个Entry的字节数
 
 public BSortMap(int capacity, int keyLen){
 this.keyLength = keyLen;
 entryLength = keyLen + 1;
 entrys = new byte[capacity * entryLength];
 }
 
 public int size(){
 return count;
 }
 
 /**
 * 添加记录条目。条目都是已经排好序的。
 * src格式为<key,value>
 * @param src
 */
 final public void add(byte src[]){
 System.arraycopy(src, 0, entrys, count * entryLength, entryLength);
 count++;
 }
 
 final private int compare(final int begin,final byte[] b){
 int i = 0;
 for (; entrys[begin+i] == b[i] && i < b.length - 1; i++)
 ;
 return entrys[begin + i] - b[i];
 }
 
 /**
 * 获取与key关联的value值
 * @param key
 * @return 如果不存在key关联的value则返回-1
 */
 final public byte get(final byte[] key){
 int i = 0;
 int j = count-1;
 int mid;
 while(i<=j){
 mid = (i + j)>>1;
 final int ret =compare(mid*entryLength,key);
 if(ret==0){
 return entrys[mid*entryLength + keyLength]; //返回结果
 } else if (ret < 0){
 i = mid+1;
 }else{
 j = mid -1;
 }
 
 }
 return -1;
 
 }
 
 public static void main(String args[]) throws IOException{
 File dir = new File("D:/workspace/partion_keyword/sort");
 File[] files = dir.listFiles();
 
 for(File f:files){
 
 DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(f)));
 /*
 * f为根据key值已经排好序的文件
 * 文件格式为:
 * entrysCount:  一个整形数字,值为总的记录条目
 * keyLength: 一个整形数字,值为关键字的字节长度
 * <key,value>列表
 */
 final int entrysCount = in.readInt();
 final int keyLength = in.readInt();
 byte[] buffer = new byte[keyLength + 1];
 BSortMap bst = new BSortMap(entrysCount,keyLength);
 int i = 0;
 while(in.available() > 0){
 int l = in.read(buffer);
 while(l != keyLength +1){
 System.err.println("not equal."+l);
 }
 bst.add(buffer);
 i++;
 }
 bulk.put(keyLength,bst);
 if (entrysCount != i)
 System.err.println(f.getName()+":"+entrysCount+","+i);
 in.close();
 }
 
 BufferedReader read = new BufferedReader(new FileReader("D:/eclipse/workspace/conf/wiki_kws.data"));
 String line ;
 int count = 0;
 long start = System.currentTimeMillis();
 while((line = read.readLine())!=null){
 byte key[] = line.trim().getBytes();
 BSortMap bt = bulk.get(key.length);
 if(bt != null && bt.get(key) != -1){
 count++;
 }
 }
 long end = System.currentTimeMillis();
 System.out.println(end - start);
 System.out.println("count:"+count);
 
 int totalcount = 0;
 for(BSortMap s: bulk.values()){
 totalcount += s.size();
 }
 System.out.println("total count:"+totalcount);
 read.close();
 
 /*while(true){
 Scanner in = new Scanner(System.in);
 String key = in.next().trim();
 if(key.equalsIgnoreCase("exit"))
 break;
 int len = key.trim().getBytes().length;
 BSort bt = bulk.get(len);
 byte v = bt.get(key.getBytes());
 System.err.println(key+"="+v);
 }*/
 
 }
 }
 测试结果:
 | 
 
类HashMap,但内存减少到原1/6的实现时间:2009-10-28 11:08:33来源:网络 作者:未知 点击:430次 java中的Map在提供方便实用的同时,也存在内存浪费巨大的问题。当Map中的Entry数量达到1000万 条以上的时候,需要数G的内存空间 .这里提到的Map使用形式为HashMap<String,Byte>,平均每个key在20个字符左右,最多不超过200
测试数据为7138595条Entry,分布在250个队列中.
HashMap<String,Byte>的结果:
时间: 3780、3814
内存: 892M
此方法的结果:
时间:5792、5758
内存: 158M
 
本篇文章来源于:开发学院 http://edu.codepub.com   原文链接:http://edu.codepub.com/2009/1028/16973_2.php