我有以下程序(完整来源):
using Mono.Unix;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
namespace StoneOS.ResourceMonitor
{
class Program
{
static void Main(string[] args)
{
var runner = new Timer(state =>
{
var cpu = CPUUsage();
var ram = RAMUsage();
var hdd = DriveUsage("/dev/sda3");
Console.WriteLine("[{0:O}] C: {1:N2} | R: {2:N2} | S: {3:N2} | H: {4:N2}", DateTime.Now, cpu, ram.Total, ram.Swap, hdd);
}, null, TimeSpan.Zero, TimeSpan.FromMilliseconds(50));
Console.ReadKey(true);
}
private static string LastReadCPULine = null;
struct Jiffy
{
public double Total;
public double Work;
}
public static double? CPUUsage()
{
// File path and descriptor, that holds the actual CPU data.
var statsFile = "/proc/stat";
// var unixInfo = new FileInfo(statsFile);
var unixInfo = new UnixFileInfo(statsFile);
// Read last queried data into cache.
string last = LastReadCPULine;
// Prepare for new read.
List<string> output = new List<string>();
// Read data.
using (var reader = new StreamReader(unixInfo.OpenRead()))
{
string currentLine;
while ((currentLine = reader.ReadLine()) != null)
{
output.Add(currentLine);
}
}
unixInfo = null; // clear...
// Select the first entry, that should be total of CPU.
string current = LastReadCPULine = output.First();
// If there was no last entry, that means we cannot calculate - return zero.
if (last == null)
{
return null;
}
return CalculateCPUUsage(last, current);
}
private static double CalculateCPUUsage(string last, string current)
{
Jiffy lastJiffy = GetJiffies(last);
Jiffy currentJiffy = GetJiffies(current);
double work = currentJiffy.Work - lastJiffy.Work;
double total = currentJiffy.Total - lastJiffy.Total;
return (work / total) * 100;
}
private static Jiffy GetJiffies(string statLine)
{
// Split on spaces.
string[] parts = subsequentSpacePattern.Split(statLine);
// Remove first entry (label - cpu).
IEnumerable<double> convertedData = parts.Skip(1).Select(entry => Convert.ToDouble(entry));
// Calculate the values for the Jiffy.
return new Jiffy
{
Total = convertedData.Sum(),
Work = convertedData.Take(3).Sum()
};
}
struct Memory
{
public double Total;
public double Swap;
}
private static Memory RAMUsage()
{
var processInfo = new ProcessStartInfo("/bin/free", "-b")
{
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
};
List<string> output = new List<string>();
using (var process = Process.Start(processInfo))
{
process.WaitForExit();
string currentLine;
using (var reader = process.StandardOutput)
{
while ((currentLine = reader.ReadLine()) != null)
{
output.Add(currentLine);
}
}
}
return new Memory
{
Total = CalculateTotalMemoryUsage(output.Skip(1).Take(1).Single()),
Swap = CalculateSwapUsage(output.Skip(2).Take(1).Single())
};
}
private static Regex subsequentSpacePattern = new Regex(@"\s+");
private static double CalculateTotalMemoryUsage(string memoryLine)
{
string[] parts = subsequentSpacePattern.Split(memoryLine);
// Console.WriteLine("[{0:O}] Memory: {1}", DateTime.Now, memoryLine);
// Console.WriteLine("[{0:O}] Memory: {1}", DateTime.Now, String.Join(", ", parts));
string totalByteString = parts.Skip(1).Take(1).Single();
string availableByteString = parts.Last();
// Console.WriteLine("[{0:O}] Total: '{1}'; Available: '{2}'", DateTime.Now, totalByteString, availableByteString);
double total = Convert.ToDouble(totalByteString);
double available = Convert.ToDouble(availableByteString);
var percentage = (available / total) * 100d;
// Console.WriteLine("[{0:O}] Memory %: {1} (Total: {2}, Free: {3})", DateTime.Now, percentage, total, available);
return 100d - percentage;
}
private static double CalculateSwapUsage(string swapLine)
{
string[] parts = subsequentSpacePattern.Split(swapLine);
// Console.WriteLine("[{0:O}] Swap: {1}", DateTime.Now, swapLine);
// Console.WriteLine("[{0:O}] Swap: {1}", DateTime.Now, String.Join(", ", parts));
string totalByteString = parts.Skip(1).Take(1).Single();
string freeByteString = parts.Last();
// Console.WriteLine("[{0:O}] Total: '{1}'; Free: '{2}'", DateTime.Now, totalByteString, freeByteString);
double total = Convert.ToDouble(totalByteString);
double free = Convert.ToDouble(freeByteString);
var percentage = (free / total) * 100d;
// Console.WriteLine("[{0:O}] Swap %: {1} (Total: {2}, Free: {3})", DateTime.Now, percentage, total, free);
// We are interested in remainder.
return 100d - percentage;
}
private static Regex multiSpacePattern = new Regex(@"\s+");
private static double DriveUsage(string drive)
{
var processInfo = new ProcessStartInfo("/bin/df", String.Format("-B1 {0}", drive))
{
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
};
List<string> output = new List<string>();
using (var process = Process.Start(processInfo))
{
process.WaitForExit();
string currentLine;
using (var reader = process.StandardOutput)
{
while ((currentLine = reader.ReadLine()) != null)
{
output.Add(currentLine);
}
}
}
// Second output line is the one we're looking for.
var second = output.Last();
string[] parts = multiSpacePattern.Split(second);
if (parts.Length != 6)
{
throw new ApplicationException(String.Format("Invalid column count in df's output: {0}", second));
}
var percentage = parts[4].TrimEnd('%');
// Console.WriteLine("Output: {0}", second);
// Console.WriteLine("[4] = {0}, percentage = {1}", parts[4], percentage);
return Convert.ToDouble(percentage);
}
}
}
只是一个基本资源监视器,它从系统读取/请求一些信息并每隔N秒报告一次。这用于反映实际应用程序中发生的错误。这种情况与实际应用程序的错误相同。周期性间隔设置为高,以便更快地获得错误以进行调试。
可以在41
&amp;线附近看到。 42
分别为:
// var unixInfo = new FileInfo(statsFile);
var unixInfo = new UnixFileInfo(statsFile);
我已经设置了两个解决方案。一个使用原生.NET/Mono
本身,另一个使用Mono.Posix
。
当使用本机解决方案(FileInfo
)运行时 - 没有问题,一切都按预期工作。
现在,当使用等效Mono.Posix
(UnixFileInfo
)时,软件最终会以System.NullReferenceException
或更差 - SIGSEGV
结束。
System.NullReferenceException
案例:
Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object at System.String.IndexOfAnyUnchecked (System.Char[] anyOf, Int32 startIndex, Int32 count) [0x00000] in :0 at System.String.IndexOfAny (System.Char[] anyOf) [0x00019] in /build/mono/src/mono-3.10.0/mcs/class/corlib/System/String.cs:896 at Mono.Unix.UnixPath.CheckPath (System.String path) [0x00000] in :0 at Mono.Unix.UnixFileSystemInfo..ctor (System.String path) [0x00000] in :0 at Mono.Unix.UnixFileInfo..ctor (System.String path) [0x00000] in :0 at StoneOS.ResourceMonitor.Program.CPUUsage () [0x00008] in /home/stone/sandbox/StoneOS.ResourceMonitor/StoneOS.ResourceMonitor/Program.cs:44 at StoneOS.ResourceMonitor.Program.m__0 (System.Object state) [0x00001] in /home/stone/sandbox/StoneOS.ResourceMonitor/StoneOS.ResourceMonitor/Program.cs:20 at System.Threading.Timer+Scheduler.TimerCB (System.Object o) [0x00007] in /build/mono/src/mono-3.10.0/mcs/class/corlib/System.Threading/Timer.cs:317
SIGSEGV
案例:
Stacktrace: Native stacktrace: /usr/lib/libmonosgen-2.0.so.1(+0xd546a) [0x7f2d9851f46a] /usr/lib/libmonosgen-2.0.so.1(+0x133aeb) [0x7f2d9857daeb] /usr/lib/libmonosgen-2.0.so.1(+0x3fde6) [0x7f2d98489de6] /usr/lib/libpthread.so.0(+0x10200) [0x7f2d9823e200] /usr/lib/libmonosgen-2.0.so.1(+0x204d70) [0x7f2d9864ed70] /usr/lib/libmonosgen-2.0.so.1(+0x20bd4f) [0x7f2d98655d4f] /usr/lib/libmonosgen-2.0.so.1(+0x20c159) [0x7f2d98656159] /usr/lib/libmonosgen-2.0.so.1(+0x229cb3) [0x7f2d98673cb3] /usr/lib/libmonosgen-2.0.so.1(+0x229d7f) [0x7f2d98673d7f] [0x4150ff33] Debug info from gdb: warning: File "/usr/bin/mono-sgen-gdb.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load". To enable execution of this file add add-auto-load-safe-path /usr/bin/mono-sgen-gdb.py line to your configuration file "/root/.gdbinit". To completely disable this security protection add set auto-load safe-path / line to your configuration file "/root/.gdbinit". For more information about this security protection see the "Auto-loading safe path" section in the GDB manual. E.g., run from the shell: info "(gdb)Auto-loading safe path" warning: Could not load shared library symbols for linux-vdso.so.1. Do you need "set solib-search-path" or "set sysroot"? [New LWP 441] [New LWP 440] [New LWP 439] [New LWP 438] [Thread debugging using libthread_db enabled] Using host libthread_db library "/usr/lib/libthread_db.so.1". 0x00007f2d97ebed57 in sigsuspend () from /usr/lib/libc.so.6 Id Target Id Frame 5 Thread 0x7f2d95c9b700 (LWP 438) "Finalizer" 0x00007f2d97ebed57 in sigsuspend () from /usr/lib/libc.so.6 4 Thread 0x7f2d956ff700 (LWP 439) "Timer-Scheduler" 0x00007f2d97ebed57 in sigsuspend () from /usr/lib/libc.so.6 3 Thread 0x7f2d954fe700 (LWP 440) "Threadpool moni" 0x00007f2d97ebed57 in sigsuspend () from /usr/lib/libc.so.6 2 Thread 0x7f2d954bd700 (LWP 441) "Threadpool work" 0x00007f2d9823ddeb in waitpid () from /usr/lib/libpthread.so.0 * 1 Thread 0x7f2d98c48780 (LWP 437) "mono" 0x00007f2d97ebed57 in sigsuspend () from /usr/lib/libc.so.6 Thread 5 (Thread 0x7f2d95c9b700 (LWP 438)): #0 0x00007f2d97ebed57 in sigsuspend () from /usr/lib/libc.so.6 #1 0x00007f2d9864cd46 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #2 #3 0x00007f2d9823c90e in sem_wait () from /usr/lib/libpthread.so.0 #4 0x00007f2d986ab5c6 in mono_sem_wait () from /usr/lib/libmonosgen-2.0.so.1 #5 0x00007f2d98624529 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #6 0x00007f2d986069e7 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #7 0x00007f2d986b0dd5 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #8 0x00007f2d98235314 in start_thread () from /usr/lib/libpthread.so.0 #9 0x00007f2d97f733ed in clone () from /usr/lib/libc.so.6 Thread 4 (Thread 0x7f2d956ff700 (LWP 439)): #0 0x00007f2d97ebed57 in sigsuspend () from /usr/lib/libc.so.6 #1 0x00007f2d9864cd46 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #2 #3 0x00007f2d9823ac68 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /usr/lib/libpthread.so.0 #4 0x00007f2d986885ba in ?? () from /usr/lib/libmonosgen-2.0.so.1 #5 0x00007f2d9869c9c2 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #6 0x00007f2d9860642f in ?? () from /usr/lib/libmonosgen-2.0.so.1 #7 0x00007f2d986078dc in ?? () from /usr/lib/libmonosgen-2.0.so.1 #8 0x000000004152a6ad in ?? () #9 0x0000000000000001 in ?? () #10 0x0000000000000001 in ?? () #11 0x0000000000000032 in ?? () #12 0x00007f2d97002cd0 in ?? () #13 0x0000000000000031 in ?? () #14 0x00007f2d880025e0 in ?? () #15 0x00007f2d956febb0 in ?? () #16 0x00007f2d956fe9f0 in ?? () #17 0x00007f2d956fe950 in ?? () #18 0x000000004152a418 in ?? () #19 0x0000000000000000 in ?? () Thread 3 (Thread 0x7f2d954fe700 (LWP 440)): #0 0x00007f2d97ebed57 in sigsuspend () from /usr/lib/libc.so.6 #1 0x00007f2d9864cd46 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #2 #3 0x00007f2d97f802ca in clock_nanosleep () from /usr/lib/libc.so.6 #4 0x00007f2d9869df48 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #5 0x00007f2d98609abe in ?? () from /usr/lib/libmonosgen-2.0.so.1 #6 0x00007f2d986069e7 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #7 0x00007f2d986b0dd5 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #8 0x00007f2d98235314 in start_thread () from /usr/lib/libpthread.so.0 #9 0x00007f2d97f733ed in clone () from /usr/lib/libc.so.6 Thread 2 (Thread 0x7f2d954bd700 (LWP 441)): #0 0x00007f2d9823ddeb in waitpid () from /usr/lib/libpthread.so.0 #1 0x00007f2d9851f500 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #2 0x00007f2d9857daeb in ?? () from /usr/lib/libmonosgen-2.0.so.1 #3 0x00007f2d98489de6 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #4 #5 0x00007f2d9864ed70 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #6 0x00007f2d98655d4f in ?? () from /usr/lib/libmonosgen-2.0.so.1 #7 0x00007f2d98656159 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #8 0x00007f2d98673cb3 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #9 0x00007f2d98673d7f in ?? () from /usr/lib/libmonosgen-2.0.so.1 #10 0x000000004150ff33 in ?? () #11 0x00007f2d973fffa0 in ?? () #12 0x00007f2d973ff108 in ?? () #13 0x000000000000001d in ?? () #14 0x00007f2d973ff108 in ?? () #15 0x0000000000000001 in ?? () #16 0x00007f2d800025e0 in ?? () #17 0x000000000000001f in ?? () #18 0x00007f2d954bc6d0 in ?? () #19 0x00007f2d954bc5e0 in ?? () #20 0x0000000041557efc in ?? () #21 0x00007f2d97000d30 in ?? () #22 0x00007f2d973fffa0 in ?? () #23 0x00007f2d973f1ae8 in ?? () #24 0x000000000000001f in ?? () #25 0x0000000000000001 in ?? () #26 0x000000000000001d in ?? () #27 0x00007f2d954bd680 in ?? () #28 0x00007f2d98673d3f in ?? () from /usr/lib/libmonosgen-2.0.so.1 #29 0x000000004150ff33 in ?? () #30 0x00007f2d97000d30 in ?? () #31 0x00007f2d973f1ae8 in ?? () #32 0x0000000000000001 in ?? () #33 0x0000000000000025 in ?? () #34 0x00007f2d973f1ae8 in ?? () #35 0x00007f2d97000d30 in ?? () #36 0x00007f2d973f1ae8 in ?? () #37 0x00007f2d97000d30 in ?? () #38 0x00007f2d954bc770 in ?? () #39 0x00000000415577e4 in ?? () #40 0x000000000000001f in ?? () #41 0x0000000000000001 in ?? () #42 0x0000000000000001 in ?? () #43 0x000000000000001c in ?? () #44 0x0000000000000001 in ?? () #45 0x0000000000000025 in ?? () #46 0x000000000000001f in ?? () #47 0x0000000000000001 in ?? () #48 0x0000000000000001 in ?? () #49 0x00007f2d973f1ae8 in ?? () #50 0x00007f2d973fffa0 in ?? () #51 0x0000000000000000 in ?? () Thread 1 (Thread 0x7f2d98c48780 (LWP 437)): #0 0x00007f2d97ebed57 in sigsuspend () from /usr/lib/libc.so.6 #1 0x00007f2d9864cd46 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #2 #3 0x00007f2d9823d3bb in read () from /usr/lib/libpthread.so.0 #4 0x00007f2d986897e1 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #5 0x00007f2d985ac234 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #6 0x0000000041530c61 in ?? () #7 0x00007f2d970168c0 in ?? () #8 0x0000000000000000 in ?? () ================================================================= Got a SIGSEGV while executing native code. This usually indicates a fatal error in the mono runtime or one of the native libraries used by your application. ================================================================= Aborted (core dumped)
但大多数时候,它都是SIGSEGV
错误。
我尝试过的......好吧,除了来自FileInfo
和UnixFileInfo
来回切换,问题是,我不知道甚至尝试什么
这是我的第一个针对Linux的主要Mono
应用程序,因此不知道该怎么做。
我已经完成了Mono GDB debugging guide - 设置提供的 .gdbinit
,与gdb
一起运行 - 结果:
Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 0x7ffff47fe700 (LWP 4558)] 0x00007ffff7a1cc47 in ?? () from /usr/lib/libmonosgen-2.0.so.1 (gdb) mono_backtrace 15 #0 0x00007ffff7a1cc47 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #1 0x00007ffff7a1caf8 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #2 0x00007ffff79f236d in ?? () from /usr/lib/libmonosgen-2.0.so.1 #3 0x00007ffff79f7725 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #4 0x00007ffff79f8159 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #5 0x00007ffff7a15cb3 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #6 0x00007ffff7a15ed4 in ?? () from /usr/lib/libmonosgen-2.0.so.1 #7 0x00007ffff79cdb16 in mono_array_new_specific () from /usr/lib/libmonosgen-2.0.so.1 #8 0x400135cb in Cannot access memory at address 0xffffffffe00f2410
这提供了默认mono --debug <path/to/exe>
没有 - mono_array_new_specific()
来电的内容,但我不知道它在这里的相关性。
我不确定这是Mono.Posix
库中的错误还是其他什么错误,但这真的让我烦恼。是的,对于这个特殊情况,我可以使用FileInfo
,但在实际应用中,我实际上正在使用UnixSymbolicLinkInfo
导致同样的问题。
mono -V
:
Mono JIT compiler version 3.10.0 (tarball Mon Oct 6 20:46:04 UTC 2014) Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com TLS: __thread SIGSEGV: altstack Notifications: epoll Architecture: amd64 Disabled: none Misc: softdebug LLVM: supported, not enabled. GC: sgen
是什么让我的应用最终最终错误地导致SIGSEGV
或System.NullReferenceException
?
答案 0 :(得分:0)
NullReferenceException绝不应该发生在类库(System.String类)中,所以这必定是一个bug。请在http://bugzilla.xamarin.com/中报告。理想情况下,在调用方法IndexOfAny()时,您应该在报告中包含所使用的字符串以及所使用的参数。为此,您可能需要检查Mono.Posix的来源,看看在Mono.Unix.UnixPath.CheckPath()中做了什么。