这太令人生气了!> _ <
我写了一个庞大而复杂的Haskell库.我写了一个小测试程序,到目前为止,我花了大约8个小时试图弄清楚为什么它一直在崩溃我.有时GHC抱怨"奇怪的封闭类型".有时我只是得到一个段错误.显然问题是内存损坏.
该库本身是100%纯Haskell.但是,测试程序使用了与阵列相关的几个不安全的GHC原语.这显然是导致问题的原因.实际上,如果我注释掉该writeArray#
行,该程序就会停止崩溃.但这对我的面条来说是完全油炸的...尽管我能说清楚,但我所使用的所有阵列边界都是完全有效的.程序将它们全部打印出来,它们都是正数且小于数组大小.
我编写了第二个程序,它与第一个程序完全相同,但没有涉及庞大,复杂的库.我尝试过并试过,但我根本无法让它崩溃.我所做的一切似乎都没有让它崩溃,但它与实际数组几乎完全相同.
有没有人有任何进一步的故障排除技巧?有什么方法可以追踪内存损坏的确切时刻吗?(而不仅仅是系统注意到腐败的那一刻.)
更新:
问题是什么?
嗯,基本上,它创建了一个表示像素缓冲区的数组.它产生一个迭代每个像素的线程,并将相应的值写入其中.它产生了第二个读取数组的线程,并使用相当复杂的协议将像素写入网络套接字.(因此我正在尝试测试的大型库.)
如果我不生成编写器线程,崩溃就会消失.如果我writeArray'
在编写器线程中注释掉调用,那么崩溃就会消失.在写入每个像素之前,写入器线程打印出像素坐标和数组索引.它打印出来的一切看起来都很完美.然而......它不会停止崩溃.
我几乎想知道GHC的数组原语是不是线程安全的还是其他东西.(如果它有任何区别,读取器线程看起来像数组的副本已被不安全冻结,而编写器线程继续同时改变它.)
但是,我编写了一个完全相同的程序,但没有通过网络发送流量.该程序在每个细节上都能完美运行.只有真正复杂的程序才行不通.这有多烦人?!
也许测试程序和带有库的程序之间的区别在于后者有更多的分配,因此更频繁地调用GC.
读者线程看起来像数组的副本已被不安全冻结,而编写器线程继续同时改变它.
可能GC无法跟踪冻结后仍然引用可变数组.在这种情况下,GC可能会移动冻结的数组,但writeArray#使用旧指针执行写入.
可能是固定的:
我更改了一些内容,并且代码不再崩溃。那可能只是a幸,或者我可能“确实”解决了这个问题。很难说。
假设:
问题似乎是从并发线程中读取同一数组的可变且不可变的副本。(即使简化测试确实做到了这一点,也不会崩溃。)
我从一个不相关的不可变数组中读取了网络线程,并且崩溃停止了。我什至添加了一个循环,将数据从一个可变数组复制到另一个新的可变数组,然后冻结并检查了新的数组。这似乎完美地工作。
因此看来,这只是GHC处理对同一阵列的两个版本的并发访问的一个小故障。
(或者,这是a幸。有几次我在程序中更改了某些内容,它停止崩溃了,然后又开始崩溃了……)
更新:这似乎是完全固定的。自从进行此更改以来,我再也没有崩溃过。感谢所有在这里帮助过我的人。:-)
归档时间: |
|
查看次数: |
1678 次 |
最近记录: |