您的位置:首页 > 其它

一个简单的笨重Map,内存中保存一些对象,其他的保存到硬盘。

2014-06-26 16:01 309 查看
今天观看论坛,发现有些初学者,总是将大量的数据存入HashMap中,造成内存溢出。

问题的关键是,造成溢出以后,不去改进算法,而是机械的调节JVM的最大内存容量,这并不能从根本上解决问题。

除了B+Tree等较好的算法以外,我想来想去,还有一个相对简单点的实现方案,就是效率硬盘没有索引,效率相对较低。

代码如下:

import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.HashSet;
import java.util.LinkedHashMap;

public class HeavyMap extends LinkedHashMap<String, Integer> {
private static final long serialVersionUID = -858815745597381386L;
public static final int DEFAULT_CAPACITY = 2000;
public static final String File_Prefix = "heavy_map";
public static final String File_Suffix = "bin";
private int capacity;// 内存对象容量
private RandomAccessFile switchFile;// 数据交换文件
private HashSet<Integer> virtualCache = new HashSet<Integer>();

public HeavyMap() throws IOException {
this(DEFAULT_CAPACITY);
}

public HeavyMap(int capacity) throws IOException {
this(capacity, File.createTempFile(File_Prefix, File_Suffix));
}

public HeavyMap(int capacity, File switchFile) throws IOException {
super(16, 0.75f, true);
this.capacity = capacity;
if (switchFile.isDirectory()) {
switchFile = File.createTempFile(File_Prefix, File_Suffix,
switchFile);
}
this.switchFile = new RandomAccessFile(switchFile, "rw");
}

@Override
public Integer put(String key, Integer value) {
virtualCache.add(key.hashCode());
return super.put(key, value);
}

@Override
protected boolean removeEldestEntry(
java.util.Map.Entry<String, Integer> eldest) {
if (size() >= capacity) {
updateEntry(eldest);
return true;
}
return false;
}

@Override
public Integer get(Object key) {
Integer value = super.get(key);
if (value == null && virtualCache.contains(key.hashCode())) {
Integer v = findValue((String) key);
if (v != null) {
put((String) key, v);
}
}
return value;
}

private Integer findValue(Object key) {
synchronized (switchFile) {
try {
switchFile.seek(0L);
long length = switchFile.length();
while (switchFile.getFilePointer() < length) {
int hash = switchFile.readInt();
int len = switchFile.readInt();
if (hash == key.hashCode()) {
byte[] data = new byte[len - 4];
if (switchFile.read(data) < 0) {
throw new EOFException();
}
int valueNumber = switchFile.readInt();
String keyString = new String(data, "UTF-8");
if (keyString.equals(key)) {
return valueNumber;
}
} else {
switchFile.skipBytes(len);
}
}
} catch (EOFException e) {
return null;
} catch (IOException e) {
throw new IllegalStateException("读取交换区数据时产生异常", e);
}
}
return null;
}

private void updateEntry(java.util.Map.Entry<String, Integer> e) {
synchronized (switchFile) {
try {
switchFile.seek(0L);
long length = switchFile.length();
while (switchFile.getFilePointer() < length) {
int hash = switchFile.readInt();
int len = switchFile.readInt();
if (hash == e.getKey().hashCode()) {
byte[] data = new byte[len - 4];
if (switchFile.read(data) < 0) {
throw new EOFException();
}
int valueNumber = switchFile.readInt();
String keyString = new String(data, "UTF-8");
if (keyString.equals(e.getKey())
&& valueNumber != e.getValue()) {
switchFile.seek(switchFile.getFilePointer() - 4);
switchFile.writeInt(e.getValue());
}
} else {
switchFile.skipBytes(len);
}
}
} catch (IOException ex) {
throw new IllegalStateException("读取交换区数据时产生异常", ex);
}
}
}

@Override
public void clear() {
super.clear();
virtualCache.clear();
}

@Override
protected void finalize() throws Throwable {
super.finalize();
switchFile.close();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐