- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
场景:我需要以数学方式处理超过 1.5GB 的文本和 csv 文件。我尝试使用 SQL Server Express,但加载信息,即使使用 BULK 导入也需要很长时间,理想情况下我需要将整个数据集放在内存中,以减少硬盘 IO。
有超过 120,000,000 条记录,但即使我尝试将信息过滤到仅一列(内存中),我的 C# 控制台应用程序也消耗约 3.5GB 的内存来处理仅 125MB(700MB 实际读入)文本。
GC 似乎没有收集对字符串和字符串数组的引用,即使在将所有引用设置为 null 并使用 using 关键字封装 IDisposables 之后也是如此。
我认为罪魁祸首是 String.Split() 方法,它为每个逗号分隔值创建一个新字符串。
您可能会建议我什至不应该将不需要的*列读入字符串数组,但这没有捕获重点:如何将这个 整个 数据集放在内存中,以便我可以处理它在 C# 中是并行的吗?
我可以优化统计算法并使用复杂的调度算法协调任务,但这是我在遇到内存问题之前希望做的事情,而不是因为。
我已经包含了一个完整的控制台应用程序,它可以模拟我的环境并且应该有助于重现问题。
感谢任何帮助。提前致谢。
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace InMemProcessingLeak
{
class Program
{
static void Main(string[] args)
{
//Setup Test Environment. Uncomment Once
//15000-20000 files would be more realistic
//InMemoryProcessingLeak.GenerateTestDirectoryFilesAndColumns(3000, 3);
//GC
GC.Collect();
//Demostrate Large Object Memory Allocation Problem (LOMAP)
InMemoryProcessingLeak.SelectColumnFromAllFiles(3000, 2);
}
}
class InMemoryProcessingLeak
{
public static List<string> SelectColumnFromAllFiles(int filesToSelect, int column)
{
List<string> allItems = new List<string>();
int fileCount = filesToSelect;
long fileSize, totalReadSize = 0;
for (int i = 1; i <= fileCount; i++)
{
allItems.AddRange(SelectColumn(i, column, out fileSize));
totalReadSize += fileSize;
Console.Clear();
Console.Out.WriteLine("Reading file {0:00000} of {1}", i, fileCount);
Console.Out.WriteLine("Memory = {0}MB", GC.GetTotalMemory(false) / 1048576);
Console.Out.WriteLine("Total Read = {0}MB", totalReadSize / 1048576);
}
Console.ReadLine();
return allItems;
}
//reads a csv file and returns the values for a selected column
private static List<string> SelectColumn(int fileNumber, int column, out long fileSize)
{
string fileIn;
FileInfo file = new FileInfo(string.Format(@"MemLeakTestFiles/File{0:00000}.txt", fileNumber));
fileSize = file.Length;
using (System.IO.FileStream fs = file.Open(FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (System.IO.StreamReader sr = new System.IO.StreamReader(fs))
{
fileIn = sr.ReadToEnd();
}
}
string[] lineDelimiter = { "\n" };
string[] allLines = fileIn.Split(lineDelimiter, StringSplitOptions.None);
List<string> processedColumn = new List<string>();
string current;
for (int i = 0; i < allLines.Length - 1; i++)
{
current = GetColumnFromProcessedRow(allLines[i], column);
processedColumn.Add(current);
}
for (int i = 0; i < lineDelimiter.Length; i++) //GC
{
lineDelimiter[i] = null;
}
lineDelimiter = null;
for (int i = 0; i < allLines.Length; i++) //GC
{
allLines[i] = null;
}
allLines = null;
current = null;
return processedColumn;
}
//returns a row value from the selected comma separated string and column position
private static string GetColumnFromProcessedRow(string line, int columnPosition)
{
string[] entireRow = line.Split(",".ToCharArray());
string currentColumn = entireRow[columnPosition];
//GC
for (int i = 0; i < entireRow.Length; i++)
{
entireRow[i] = null;
}
entireRow = null;
return currentColumn;
}
#region Generators
public static void GenerateTestDirectoryFilesAndColumns(int filesToGenerate, int columnsToGenerate)
{
DirectoryInfo dirInfo = new DirectoryInfo("MemLeakTestFiles");
if (!dirInfo.Exists)
{
dirInfo.Create();
}
Random seed = new Random();
string[] columns = new string[columnsToGenerate];
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= filesToGenerate; i++)
{
int rows = seed.Next(10, 8000);
for (int j = 0; j < rows; j++)
{
sb.Append(GenerateRow(seed, columnsToGenerate));
}
using (TextWriter tw = new StreamWriter(String.Format(@"{0}/File{1:00000}.txt", dirInfo, i)))
{
tw.Write(sb.ToString());
tw.Flush();
}
sb.Remove(0, sb.Length);
Console.Clear();
Console.Out.WriteLine("Generating file {0:00000} of {1}", i, filesToGenerate);
}
}
private static string GenerateString(Random seed)
{
StringBuilder sb = new StringBuilder();
int characters = seed.Next(4, 12);
for (int i = 0; i < characters; i++)
{
sb.Append(Convert.ToChar(Convert.ToInt32(Math.Floor(26 * seed.NextDouble() + 65))));
}
return sb.ToString();
}
private static string GenerateRow(Random seed, int columnsToGenerate)
{
StringBuilder sb = new StringBuilder();
sb.Append(seed.Next());
for (int i = 0; i < columnsToGenerate - 1; i++)
{
sb.Append(",");
sb.Append(GenerateString(seed));
}
sb.Append("\n");
return sb.ToString();
}
#endregion
}
}
*在程序的整个生命周期中,这些其他列将被需要并按顺序和随机访问,因此每次从磁盘读取都是非常繁重的开销。
**环境说明:4GB DDR2 SDRAM 800、Core 2 Duo 2.5Ghz、.NET Runtime 3.5 SP1、Vista 64。
最佳答案
是的,String.Split 为每个“片段”创建一个新的 String 对象——这就是它的本意。
现在,请记住 .NET 中的字符串是 Unicode(实际上是 UTF-16),加上对象开销,字符串的字节成本大约是 20 + 2*n
其中 n
是字符数。
这意味着如果您有很多小字符串,与所涉及的文本数据的大小相比,它会占用大量内存。例如,将 80 个字符的行拆分为 10 x 8 个字符串将占用文件中的 80 个字节,但 10 * (20 + 2*8) = 360 个字节的内存 - 4.5 倍的爆炸!
我怀疑这是一个 GC 问题 - 我建议您在不需要时删除将变量设置为 null 的额外语句 - 只是数据过多的问题。
我会建议您逐行阅读文件(使用 TextReader.ReadLine()
而不是 TextReader.ReadToEnd()
)。如果不需要,显然将整个文件保存在内存中是一种浪费。
关于c# - 为什么我不能利用计算机中的 4GB RAM 来处理 C# 中少于 2GB 的信息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/704350/
有没有办法在不进行提交/ check out 的情况下应用差异补丁或类似补丁? 我的情况:我工作时经常在计算机之间切换,我的提交历史记录有一堆“switching machines”消息。 我最初的猜
我的自定义引导加载程序中有代码从地址 0x8E00 处的 512 字节缓冲区复制内存。进入高内存,0x100000和更高。这在某些计算机上运行良好,而在其他计算机上崩溃(我假设是三重故障)。此代码在
服务器有没有办法将一些数据无线无缝地推送到客户端,可能是 Windows(电话)、iPhone、Mac 或 Android 设备,没有任何操作系统集成? 如果是这样,最好的设计模式是什么,最好的技术是
我无法理解hadoop的真正本质。 如果我有足够的资源来购买可以处理PB级数据的 super 计算机,那么为什么我需要Hadoop基础架构来管理如此大的数据? 最佳答案 hadoop的全部目的是能够在
我有一个奇怪的问题,或者我可能无法理解Grails i18n机制的工作原理。 我将以下内容插入到index.gsp文件中: LocaleContextHolder.locale:
我正在尝试为我的小弟弟编写一个简单的程序。他经常在他的电脑后面,但他应该为学校学习简单的算术 :D 我想制作以下程序: 他启动了他的电脑 他需要做一些简单的练习并完成 如果他做对了 x 次,他可以继续
有人能告诉我如何在 diff 主机(计算机)上为 MySQL 数据库做一个简单的数据库备份吗?我正在尝试将我的数据库从一台主机(服务器)移动到一台新主机(服务器) 最佳答案 如果您只是需要在服务器之间
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是无关紧要的,因
我正在尝试让 Android 应用程序使用 USB 电缆与运行 ubuntu 12.04 lts 的 Linux 计算机进行通信。我正在尝试使用 usbdeviceconnection 类,但是当我通
我刚刚使用 docker-toolbox 1.8.2 安装了 docker在 Windows 10 上。 由于由于this issue我不得不使用这些命令重新创建 docker 镜像 docker-m
如何删除处于 GURU_MEDITATION 错误状态的 VirtualBox 计算机?在 VirtualBox 未运行时删除该目录是否足够? 编辑:发布后,我删除了“在文件管理器中显示”导航到的整个
当我们在 Azure 机器学习服务中将模型部署为 ACIWebService 时,不需要指定任何 deployment_target。 根据AzureML documentation对于 azurem
当我们在 Azure 机器学习服务中将模型部署为 ACIWebService 时,不需要指定任何 deployment_target。 根据AzureML documentation对于 azurem
我遇到的主要问题是当我选择 stay 时会发生什么上hand_one ,然后 hit上hand_two . 而不是让我hit or stay上hand_two再次,它让我回到hit or stay上h
我知道我可以使用 putty 来 ssh 进入每台 Linux 机器并更新 CentOS 服务器...但我希望有人能够为我指明正确的方向,告诉我如何通过 PowerShell 或 Windows 中的
在 MIX 计算机中,一个单词由五个字节和一个符号组成。符号在内存中是如何表示的?是另一个字节,所以每个字真的是六个字节吗? 谢谢。 最佳答案 你的问题不是很清楚。体系结构规范未指定实际实现。它仅指定
我是 Python 的初级程序员,我的电脑有一个奇怪的问题。当我的计算机上有一个 .py 文件(包含一个有效的脚本)并双击它打开时,会发生以下情况:程序打开(它是黑屏 View ),但它会在一秒钟内自
我正在尝试在 Windows 上使用 plink 创建到 Linux 机器的隧道,并让转储文件最终出现在 Windows 机器上。看起来 this answer会工作,是我的问题的基础。但是尝试一下并
我想在 Windows 7 和 10 计算机上执行重启,但我首先需要将 Jenkins 节点暂时离线。在执行重启之前,我需要完成所有正在运行的任务。然后我远程登录到服务器并重新启动计算机。然而,在我重
我正在编写一个简单的程序,从 MySQL 数据库中提取计算机名称,然后将这些名称存储到字符串数组列表中(这部分工作正常)。之后,我编写了一个类和一个方法,将字符串作为参数(这将是计算机名称)并尝试对其
我是一名优秀的程序员,十分优秀!