写了段小程序,读一个300M左右的文件,共100万个不同id结点,2200万行。文件内容只有两列,如下:
3,6
3,7
3,16
20,31
20,35
20,36
……其中3,6表示id为3的用户关注了id为6的用户。我写的程序是把这个文件读入内存,接收的数据结构有三个:
HashSet<Integer> set //结点id的集合
HashMap<Integer, LinkedList<Integer>> inlinkMap //映射关系为 id->follower ids
HashMap<Integer, LinkedList<Integer>> outlinkMap //映射关系为 id->followee ids
代码如下:(关键代码只有中间一小段,前面是变量定义,后面是异常处理)private void format(String fileName, Set<Integer> set, HashMap< Integer, LinkedList<Integer> > inlinkMap,
HashMap<Integer,LinkedList<Integer> > outlinkMap)
{
System.out.println("Loading...");
FileReader fr = null;
BufferedReader br = null;
LinkedList<Integer> inlinkList = null;
LinkedList<Integer> outlinkList = null;
String strLine = null;
int seperatorIndex, followerId, followeeId;
try {
fr = new FileReader(fileName);
br = new BufferedReader(fr);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
while(true)
{
try
{
strLine = br.readLine();
seperatorIndex = strLine.indexOf(',');
followerId = Integer.parseInt(strLine.substring(0, seperatorIndex));
followeeId = Integer.parseInt(strLine.substring(seperatorIndex+1,strLine.length()));
if(!set.contains(followerId))
{
set.add(followerId);
}
if(!set.contains(followeeId))
{
set.add(followeeId);
}
if(!inlinkMap.keySet().contains(followeeId))
{
inlinkList = new LinkedList<Integer>();
inlinkList.add(followerId);
inlinkMap.put(followeeId, inlinkList);
}
else
{
inlinkList = inlinkMap.get(followeeId);
inlinkList.add(followerId);
}
if(!outlinkMap.keySet().contains(followerId))
{
outlinkList = new LinkedList<Integer>();
outlinkList.add(followeeId);
outlinkMap.put(followerId, outlinkList);
}
else
{
outlinkList = outlinkMap.get(followerId);
outlinkList.add(followeeId);
}
} catch(Exception e)
{
System.out.println("EOF");
try {
br.close();
fr.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
break;
}
}
try {
br.close();
fr.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Loading completed!"); }
运行的时候,我用java -Xms2048m -Xmx8192m XXXXX 命令,分配了8G的内存才能成功,8G以下都提示内存不足。
是不是用HashMap太占内存了?还是我用HashMap的方法不对?
求解脱……
3,6
3,7
3,16
20,31
20,35
20,36
……其中3,6表示id为3的用户关注了id为6的用户。我写的程序是把这个文件读入内存,接收的数据结构有三个:
HashSet<Integer> set //结点id的集合
HashMap<Integer, LinkedList<Integer>> inlinkMap //映射关系为 id->follower ids
HashMap<Integer, LinkedList<Integer>> outlinkMap //映射关系为 id->followee ids
代码如下:(关键代码只有中间一小段,前面是变量定义,后面是异常处理)private void format(String fileName, Set<Integer> set, HashMap< Integer, LinkedList<Integer> > inlinkMap,
HashMap<Integer,LinkedList<Integer> > outlinkMap)
{
System.out.println("Loading...");
FileReader fr = null;
BufferedReader br = null;
LinkedList<Integer> inlinkList = null;
LinkedList<Integer> outlinkList = null;
String strLine = null;
int seperatorIndex, followerId, followeeId;
try {
fr = new FileReader(fileName);
br = new BufferedReader(fr);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
while(true)
{
try
{
strLine = br.readLine();
seperatorIndex = strLine.indexOf(',');
followerId = Integer.parseInt(strLine.substring(0, seperatorIndex));
followeeId = Integer.parseInt(strLine.substring(seperatorIndex+1,strLine.length()));
if(!set.contains(followerId))
{
set.add(followerId);
}
if(!set.contains(followeeId))
{
set.add(followeeId);
}
if(!inlinkMap.keySet().contains(followeeId))
{
inlinkList = new LinkedList<Integer>();
inlinkList.add(followerId);
inlinkMap.put(followeeId, inlinkList);
}
else
{
inlinkList = inlinkMap.get(followeeId);
inlinkList.add(followerId);
}
if(!outlinkMap.keySet().contains(followerId))
{
outlinkList = new LinkedList<Integer>();
outlinkList.add(followeeId);
outlinkMap.put(followerId, outlinkList);
}
else
{
outlinkList = outlinkMap.get(followerId);
outlinkList.add(followeeId);
}
} catch(Exception e)
{
System.out.println("EOF");
try {
br.close();
fr.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
break;
}
}
try {
br.close();
fr.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Loading completed!"); }
运行的时候,我用java -Xms2048m -Xmx8192m XXXXX 命令,分配了8G的内存才能成功,8G以下都提示内存不足。
是不是用HashMap太占内存了?还是我用HashMap的方法不对?
求解脱……
解决方案 »
- 初学JDBC问题---No database selected
- 问JAVA学习的重点
- java入门问题
- 空指针错误原因找到了,可是不知道该怎么样解决
- 关于Chanset、FileChannel类设计上的一个疑问
- [求助]一个类如何编程线程安全的?
- 《Thinking in Java》上的题目,大家帮忙看看
- JavaBean 之间调用,Bean结构问题?-----急----100分
- 我在红帽Linux下用rpm -i j2sdk-1_3_0-linux.rpm安装了jdk1.3,java装载到了/usr/java下,接下来我该how to do?
- 大家来评评java的bug.
- 怎样调用方法效率高
- 这样的Exception该如何解决?
HashMap<Integer, LinkedList<Integer>> outlinkMap //映射关系为 id->followee ids占内存,每一个ID对应一个新的链表对象...链表的对象对而大。
比如:1对应234567890
2对应134567890里面的34567890都是重复存储...占用多了实际文件的一倍..
HashMap<Integer, LinkedList<Integer>> outlinkMap //映射关系为 id->followee ids占内存,每一个ID对应一个新的链表对象...链表的对象对而大。
比如:1对应234567890
2对应134567890里面的34567890都是重复存储...占用多了实际文件的一倍..
还行吧,才300M而已,只针对这个情况来说,我只想知道为什么300M的文件加载到内存要占8G,内存吃在什么地方?
-Xms20m -Xmx40m 40M空间,只够存储151W左右的数据。
public class Test {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
int i = 0;
try {
for (i = 0; i < Integer.MAX_VALUE; i++) {
list.add(i);
}
} finally {
System.out.println(i);
}
}
}
计算一下:100Set 50M
100W Map = 100/6.5 * 40 = 615M * 2 = 1.3G + 50M暂时只能计算到这么多,最好再检查一下程序,是不是多创建了对象。
上面的List用的ArrayList
如果为LinkedList只能存储1.6W左右的数据。
100/1.6 * 40 = 2500M * 2 + 50M = 5G请先将LinkedList换为ArrayList
哥们你太让我感动了,比我还耐心测……我也好好试试去! 但仍期待大牛能一语道破机关~我看了下数据集,对于Map<Integer,List<Integer>> List中平均有22.9条数据。你说的是LinkedList比较占内存哈,恩……
其实我之所以用LinkedList而不用ArrayList,是认为LinkedList适合插入、遍历操作,而ArrayList适合遍历、检索操作。我再试试~
{
set.add(followerId);
}
if(!set.contains(followeeId))
{
set.add(followeeId);
}
这个 比较是多余的。set他自己也会比较一次。
HashMap<Integer, LinkedList<Integer>> inlinkMap,
HashMap<Integer, LinkedList<Integer>> outlinkMap){
System.out.println("Loading...");
FileReader fr = null;
BufferedReader br = null;
LinkedList<Integer> inlinkList = null;
LinkedList<Integer> outlinkList = null;
String strLine = null;
String[] temp = null;
int followerId, followeeId; try {
fr = new FileReader(fileName);
br = new BufferedReader(fr);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
while ((strLine = br.readLine()) != null) {
temp = strLine.split("[,]");
followerId = Integer.valueOf(temp[0]);
followeeId = Integer.valueOf(temp[1]);
set.add(followerId);
set.add(followeeId);
if (!inlinkMap.keySet().contains(followeeId)){
inlinkList = new LinkedList<Integer>();
inlinkList.add(followerId);
inlinkMap.put(followeeId, inlinkList);
} else {
inlinkMap.get(followeeId).add(followerId);
} if (!outlinkMap.keySet().contains(followerId)) {
outlinkList = new LinkedList<Integer>();
outlinkList.add(followeeId);
outlinkMap.put(followerId, outlinkList);
} else {
outlinkMap.get(followerId).add(followeeId);
}
}
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
System.out.println("Loading completed!");
try {
br.close();
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
不是从中间插入删除的话,用arrayList快一些
private static void format02(String fileName, Set<Integer> set, Map<Integer, List<Integer>> inlinkMap,
Map<Integer, List<Integer>> outlinkMap) throws NumberFormatException, IOException
{
System.out.println("Loading...");
BufferedReader br = null;
int seperatorIndex, followerId, followeeId;
try
{
br = new BufferedReader(new FileReader(fileName));
String strLine = null;
while ((strLine = br.readLine()) != null)
{
seperatorIndex = strLine.indexOf(',');
followerId = Integer.parseInt(strLine.substring(0, seperatorIndex));
followeeId = Integer.parseInt(strLine.substring(seperatorIndex + 1, strLine.length()));
set.add(followerId);
set.add(followeeId);
if (!inlinkMap.containsKey(followeeId))
{
List<Integer> inlinkList = new ArrayList<Integer>();
inlinkList.add(followerId);
inlinkMap.put(followeeId, inlinkList);
}
else
{
inlinkMap.get(followeeId).add(followerId);;
}
if (!outlinkMap.containsKey(followerId))
{
List<Integer> outlinkList = new ArrayList<Integer>();
outlinkList.add(followeeId);
outlinkMap.put(followerId, outlinkList);
}
else
{
outlinkMap.get(followerId).add(followeeId);
}
}
}
finally
{
if (br != null)
{
br.close();
br = null;
} }
}400W数据,200000用户的条件下:
性能提升:23%
内存占用少:36%主要提升点在:1. linklist变为arraylist(性能和内存的提升)
2. set.add(followerId); (内存减少4%左右)
比如map容量为100,加载因子为0.75 当数据达到76条时,Map的容量会扩充为200。如果仅有76条数据,那么剩余的空间白白的消耗内存。
ArrayList,HashSet也是一样。合理的初始化map长度,也有助于提升性能以及节约内存。
你下面的代码我也学习了,String的split函数~
恩,刚试了试,用
Runtime runtime = Runtime.getRuntime();
runtime.totalMemory() - runtime.freeMemory();
算内存使用量,这方法不知道对不对。
对Map的value数据结构选择 ArrayList LinkedList HashSet,数据量1w个结点,13w条边
结果是:
(ArrayList版) Memory:9010976B(约9M)
(LinkedList版)Memory:12402184B(约12M)
(HashSet版) Memory:16480688B(约16M)
其他人的回复我没看。但是我觉得。
你
3,6
3,7
3,16为嘛不做成ID3 List6,7,16
去看看吧,测试java几个集合的内存消耗情况。
另外,默认hashMap最少会空闲25%的数据空间出来,
Map map = new HashMap(1000000,1.0f);
nice~ 挖到不错的技术网站
(1)这两列数据的长度已知,读入内存后可以用一个二维数组(或者两个一维数组)来保存吧,这样效率会高点。
(2)可以边读,边操作,即一段一段的读,用LineNumberReader,用(),reset()等打个记号,这样用很小的内存就可以搞定。