首页 \ 问答 \ PHP脚本在每次迭代时花费的时间越来越长,以保存数据(PHP script taking longer and longer on each iteration to save data)

PHP脚本在每次迭代时花费的时间越来越长,以保存数据(PHP script taking longer and longer on each iteration to save data)

我编写了一个自动化脚本来解析本地的XML文件,从XML中提取一些URL,然后下载URL指向的文件并存储数据(所有jpg)。 每次后续迭代都会逐渐变长。 最终,脚本挂起,没有任何反应。 哦,内存使用似乎保持不变。 XML解析工作正常,所以请不要过多地讨论它。 如果我在脚本完全停止的游戏中启动脚本,则会在一秒钟内将文件保存到磁盘,因为这是脚本执行的第一次保存。 是什么造成的? 这是代码:

    <?php

$xml = simplexml_load_file('./playfin.xml', null, LIBXML_NOCDATA);

echo("Getting urls from the XML...\n");
$data = array();
foreach($xml->game as $game) {
  $smlBox = $game->small_boxshot_image->url;
  $lrgBox = $game->large_boxshot_image->url;

  foreach($game->screenshots->screenshot_image as $image) {
    $scrShots[] = array(
      'smlScr' => (string)$image->small_screenshot_image->url,
      'lrgScr' => (string)$image->large_screenshot_image->url  
    );
  }
  $data[] = array(
    'id' => (int)$game->game_id,
    'smlBox' => (string)$smlBox,
    'lrgBox' => (string)$lrgBox,
    'scrShots' => $scrShots
  );
} 
echo("Done pulling urls from XML...\n");

echo("Storing picture data to disk...\n");
$start = time();
$total = 0;
$now = 0;
for($i = 0; $i < count($data); $i++) {
  $total += $now;
  $now = time() - $start - $total;
  echo("Writing game id: ".$data[$i]['id']. 
    ." to disk at time=".(string)$now."          seconds.\n");
  echo("Memory usage: ".(string)memory_get_usage(true)."\n\n");
  $smlBoxStr = '%s_49_60.jpg';
  $lrgBoxStr = '%s_160_189.jpg';
  $smlScrStr = '%s_115_86_%d.jpg';
  $lrgScrStr = '%s_300_300_%d.jpg';

  writeData($data[$i]['smlBox'], sprintf($smlBoxStr, $data[$i]['id']), 'boxshot');
  writeData($data[$i]['lrgBox'], sprintf($lrgBoxStr, $data[$i]['id']), 'boxshot');
  for($j = 0; $j < count($data[$i]['scrShots']); $j++) {
    writeData(
      $data[$i]['scrShots'][$j]['smlScr'], 
      sprintf($smlScrStr, $data[$i]['id'], $j),
      'screenshot'
    );
    writeData(
      $data[$i]['scrShots'][$j]['lrgScr'], 
      sprintf($lrgScrStr, $data[$i]['id'], $j),
      'screenshot'
    );
  }  
}
echo("Done storing!\n");
echo("Done!\n");

function writeData($url, $file, $type) {
  $headers = get_headers($url, 1);
  $awayPic = fopen($url, 'rb');
  $localPic = fopen("./$type/$file", 'wb');
  while($picData = fread($awayPic, (int)$headers['Content-Length'])) {
    fwrite($localPic, $picData);
  }
  fclose($awayPic);
  fclose($localPic);
}  

?>

这是生成的日志文件:

从XML获取网址...从XML中提取网址...将图片数据存储到磁盘...将游戏ID:671850写入磁盘时间= 0秒。 内存使用情况:77856768

在时间= 0秒时将游戏ID:730950写入磁盘。 内存使用情况:77856768

在时间= 1秒时将游戏ID:621650写入磁盘。 内存使用情况:77856768

在时间= 1秒时将游戏ID:687250写入磁盘。 内存使用情况:77856768

在时间= 7秒时将游戏ID:633950写入磁盘。 内存使用情况:77856768

在时间= 2秒时将游戏ID:633850写入磁盘。 内存使用情况:77856768

在时间= 2秒时将游戏ID:720950写入磁盘。 内存使用情况:77856768

在时间= 3秒时将游戏ID:572250写入磁盘。 内存使用情况:77856768

在时间= 3秒时将游戏ID:674950写入磁盘。 内存使用情况:77856768

在时间= 3秒时将游戏ID:731450写入磁盘。 内存使用情况:77856768

将游戏ID:656350写入磁盘时间= 4秒。 内存使用情况:77856768

在时间= 4秒时将游戏ID:653550写入磁盘。 内存使用情况:77856768

在时间= 4秒时将游戏ID:585550写入磁盘。 内存使用情况:77856768

在时间= 5秒时将游戏ID:736750写入磁盘。 内存使用情况:77856768

在时间= 5秒时将游戏ID:671350写入磁盘。 内存使用情况:77856768

在时间= 5秒时将游戏ID:696250写入磁盘。 内存使用情况:77856768

在时间= 6秒时将游戏ID:645550写入磁盘。 内存使用情况:77856768

在时间= 6秒时将游戏ID:625650写入磁盘。 内存使用情况:77856768

在时间= 6秒时将游戏ID:696850写入磁盘。 内存使用情况:77856768

在时间= 7秒时将游戏ID:709550写入磁盘。 内存使用情况:77856768

在时间= 7秒时将游戏ID:575750写入磁盘。 内存使用情况:77856768

将游戏ID:651950写入磁盘时间= 7秒。 内存使用情况:77856768

在时间= 8秒时将游戏ID:685350写入磁盘。 内存使用情况:77856768

在时间= 9秒时将游戏ID:724150写入磁盘。 内存使用情况:77856768

在时间= 8秒时将游戏ID:522250写入磁盘。 内存使用情况:77856768

在时间= 10秒时将游戏ID:610350写入磁盘。 内存使用情况:77856768

在时间= 9秒时将游戏ID:645050写入磁盘。 内存使用情况:77856768

在时间= 9秒时将游戏ID:716950写入磁盘。 内存使用情况:77856768

在时间= 10秒时将游戏ID:672750写入磁盘。 内存使用情况:77856768

在时间= 11秒时将游戏ID:568650写入磁盘。 内存使用情况:77856768

在时间= 11秒时将游戏ID:668650写入磁盘。 内存使用情况:77856768

在时间= 11秒时将游戏ID:417950写入磁盘。 内存使用情况:77856768

在时间= 13秒时将游戏ID:497950写入磁盘。 内存使用情况:77856768

在时间= 12秒时将游戏ID:567950写入磁盘。 内存使用情况:77856768

在时间= 13秒时将游戏ID:692350写入磁盘。 内存使用情况:77856768

在时间= 13秒时将游戏ID:450950写入磁盘。 内存使用情况:77856768

在时间= 14秒时将游戏ID:452750写入磁盘。 内存使用情况:77856768

在时间= 14秒时将游戏ID:666450写入磁盘。 内存使用情况:77856768

在时间= 15秒时将游戏ID:754550写入磁盘。 内存使用情况:77856768

在时间= 15秒时将游戏ID:659050写入磁盘。 内存使用情况:77856768

在时间= 15秒时将游戏ID:712350写入磁盘。 内存使用情况:77856768

在时间= 16秒时将游戏ID:719250写入磁盘。 内存使用情况:77856768

在时间= 15秒时将游戏ID:529250写入磁盘。 内存使用情况:77856768

在时间= 17秒时将游戏ID:685150写入磁盘。 内存使用情况:77856768

在时间= 17秒时将游戏ID:736450写入磁盘。 内存使用情况:77856768

在时间= 17秒时将游戏ID:252750写入磁盘。 内存使用情况:77856768

在时间= 17秒时将游戏ID:719150写入磁盘。 内存使用情况:77856768

在时间= 18秒时将游戏ID:461150写入磁盘。 内存使用情况:77856768

在时间= 18秒时将游戏ID:699450写入磁盘。 内存使用情况:77856768

在时间= 18秒时将游戏ID:523550写入磁盘。 内存使用情况:77856768

在时间= 20秒时将游戏ID:451050写入磁盘。 内存使用情况:77856768

在时间= 19秒时将游戏ID:768350写入磁盘。 内存使用情况:77856768

在时间= 20秒时将游戏ID:724650写入磁盘。 内存使用情况:77856768

在时间= 21秒时将游戏ID:676550写入磁盘。 内存使用情况:77856768

在时间= 21秒时将游戏ID:730850写入磁盘。 内存使用情况:77856768

在时间= 22秒时将游戏ID:558250写入磁盘。 内存使用情况:77856768

在时间= 22秒时将游戏ID:674750写入磁盘。 内存使用情况:77856768

在时间= 22秒时将游戏ID:695450写入磁盘。 内存使用情况:77856768

在时间= 22秒时将游戏ID:682950写入磁盘。 内存使用情况:77856768

在时间= 24秒时将游戏ID:706450写入磁盘。 内存使用情况:77856768

在时间= 24秒时将游戏ID:546450写入磁盘。 内存使用情况:77856768

在时间= 24秒时将游戏ID:575350写入磁盘。 内存使用情况:77856768

在时间= 25秒时将游戏ID:616550写入磁盘。 内存使用情况:77856768

在时间= 26秒时将游戏ID:648250写入磁盘。 内存使用情况:77856768

在时间= 25秒时将游戏ID:763750写入磁盘。 内存使用情况:77856768

在时间= 26秒时将游戏ID:613850写入磁盘。 内存使用情况:77856768

在时间= 25秒时将游戏ID:645450写入磁盘。 内存使用情况:77856768

在时间= 33秒时将游戏ID:695950写入磁盘。 内存使用情况:77856768

在时间= 27秒时将游戏ID:661050写入磁盘。 内存使用情况:77856768

在时间= 27秒时将游戏ID:461050写入磁盘。 内存使用情况:77856768

在时间= 29秒时将游戏ID:693150写入磁盘。 内存使用情况:77856768

谢谢!


I wrote an automation script to parse an XML file on local, pull some urls from the XML, and then download the files pointed to by the urls and store the data(all jpg's). Every subsequent iteration progressively takes longer and longer. Eventually, the script just hangs and nothing happens. Oh, the memory usage appears to remain constant. The XML parsing works fine, so please don't dwell on that too much. If I start the script at a game where the script stops altogether, is saves the files to disk in under a second, because it is the first save the script does. What is causing this? Here's the code:

    <?php

$xml = simplexml_load_file('./playfin.xml', null, LIBXML_NOCDATA);

echo("Getting urls from the XML...\n");
$data = array();
foreach($xml->game as $game) {
  $smlBox = $game->small_boxshot_image->url;
  $lrgBox = $game->large_boxshot_image->url;

  foreach($game->screenshots->screenshot_image as $image) {
    $scrShots[] = array(
      'smlScr' => (string)$image->small_screenshot_image->url,
      'lrgScr' => (string)$image->large_screenshot_image->url  
    );
  }
  $data[] = array(
    'id' => (int)$game->game_id,
    'smlBox' => (string)$smlBox,
    'lrgBox' => (string)$lrgBox,
    'scrShots' => $scrShots
  );
} 
echo("Done pulling urls from XML...\n");

echo("Storing picture data to disk...\n");
$start = time();
$total = 0;
$now = 0;
for($i = 0; $i < count($data); $i++) {
  $total += $now;
  $now = time() - $start - $total;
  echo("Writing game id: ".$data[$i]['id']. 
    ." to disk at time=".(string)$now."          seconds.\n");
  echo("Memory usage: ".(string)memory_get_usage(true)."\n\n");
  $smlBoxStr = '%s_49_60.jpg';
  $lrgBoxStr = '%s_160_189.jpg';
  $smlScrStr = '%s_115_86_%d.jpg';
  $lrgScrStr = '%s_300_300_%d.jpg';

  writeData($data[$i]['smlBox'], sprintf($smlBoxStr, $data[$i]['id']), 'boxshot');
  writeData($data[$i]['lrgBox'], sprintf($lrgBoxStr, $data[$i]['id']), 'boxshot');
  for($j = 0; $j < count($data[$i]['scrShots']); $j++) {
    writeData(
      $data[$i]['scrShots'][$j]['smlScr'], 
      sprintf($smlScrStr, $data[$i]['id'], $j),
      'screenshot'
    );
    writeData(
      $data[$i]['scrShots'][$j]['lrgScr'], 
      sprintf($lrgScrStr, $data[$i]['id'], $j),
      'screenshot'
    );
  }  
}
echo("Done storing!\n");
echo("Done!\n");

function writeData($url, $file, $type) {
  $headers = get_headers($url, 1);
  $awayPic = fopen($url, 'rb');
  $localPic = fopen("./$type/$file", 'wb');
  while($picData = fread($awayPic, (int)$headers['Content-Length'])) {
    fwrite($localPic, $picData);
  }
  fclose($awayPic);
  fclose($localPic);
}  

?>

Here's the log file that was produced:

Getting urls from the XML... Done pulling urls from XML... Storing picture data to disk... Writing game id: 671850 to disk at time=0 seconds. Memory usage: 77856768

Writing game id: 730950 to disk at time=0 seconds. Memory usage: 77856768

Writing game id: 621650 to disk at time=1 seconds. Memory usage: 77856768

Writing game id: 687250 to disk at time=1 seconds. Memory usage: 77856768

Writing game id: 633950 to disk at time=7 seconds. Memory usage: 77856768

Writing game id: 633850 to disk at time=2 seconds. Memory usage: 77856768

Writing game id: 720950 to disk at time=2 seconds. Memory usage: 77856768

Writing game id: 572250 to disk at time=3 seconds. Memory usage: 77856768

Writing game id: 674950 to disk at time=3 seconds. Memory usage: 77856768

Writing game id: 731450 to disk at time=3 seconds. Memory usage: 77856768

Writing game id: 656350 to disk at time=4 seconds. Memory usage: 77856768

Writing game id: 653550 to disk at time=4 seconds. Memory usage: 77856768

Writing game id: 585550 to disk at time=4 seconds. Memory usage: 77856768

Writing game id: 736750 to disk at time=5 seconds. Memory usage: 77856768

Writing game id: 671350 to disk at time=5 seconds. Memory usage: 77856768

Writing game id: 696250 to disk at time=5 seconds. Memory usage: 77856768

Writing game id: 645550 to disk at time=6 seconds. Memory usage: 77856768

Writing game id: 625650 to disk at time=6 seconds. Memory usage: 77856768

Writing game id: 696850 to disk at time=6 seconds. Memory usage: 77856768

Writing game id: 709550 to disk at time=7 seconds. Memory usage: 77856768

Writing game id: 575750 to disk at time=7 seconds. Memory usage: 77856768

Writing game id: 651950 to disk at time=7 seconds. Memory usage: 77856768

Writing game id: 685350 to disk at time=8 seconds. Memory usage: 77856768

Writing game id: 724150 to disk at time=9 seconds. Memory usage: 77856768

Writing game id: 522250 to disk at time=8 seconds. Memory usage: 77856768

Writing game id: 610350 to disk at time=10 seconds. Memory usage: 77856768

Writing game id: 645050 to disk at time=9 seconds. Memory usage: 77856768

Writing game id: 716950 to disk at time=9 seconds. Memory usage: 77856768

Writing game id: 672750 to disk at time=10 seconds. Memory usage: 77856768

Writing game id: 568650 to disk at time=11 seconds. Memory usage: 77856768

Writing game id: 668650 to disk at time=11 seconds. Memory usage: 77856768

Writing game id: 417950 to disk at time=11 seconds. Memory usage: 77856768

Writing game id: 497950 to disk at time=13 seconds. Memory usage: 77856768

Writing game id: 567950 to disk at time=12 seconds. Memory usage: 77856768

Writing game id: 692350 to disk at time=13 seconds. Memory usage: 77856768

Writing game id: 450950 to disk at time=13 seconds. Memory usage: 77856768

Writing game id: 452750 to disk at time=14 seconds. Memory usage: 77856768

Writing game id: 666450 to disk at time=14 seconds. Memory usage: 77856768

Writing game id: 754550 to disk at time=15 seconds. Memory usage: 77856768

Writing game id: 659050 to disk at time=15 seconds. Memory usage: 77856768

Writing game id: 712350 to disk at time=15 seconds. Memory usage: 77856768

Writing game id: 719250 to disk at time=16 seconds. Memory usage: 77856768

Writing game id: 529250 to disk at time=15 seconds. Memory usage: 77856768

Writing game id: 685150 to disk at time=17 seconds. Memory usage: 77856768

Writing game id: 736450 to disk at time=17 seconds. Memory usage: 77856768

Writing game id: 252750 to disk at time=17 seconds. Memory usage: 77856768

Writing game id: 719150 to disk at time=17 seconds. Memory usage: 77856768

Writing game id: 461150 to disk at time=18 seconds. Memory usage: 77856768

Writing game id: 699450 to disk at time=18 seconds. Memory usage: 77856768

Writing game id: 523550 to disk at time=18 seconds. Memory usage: 77856768

Writing game id: 451050 to disk at time=20 seconds. Memory usage: 77856768

Writing game id: 768350 to disk at time=19 seconds. Memory usage: 77856768

Writing game id: 724650 to disk at time=20 seconds. Memory usage: 77856768

Writing game id: 676550 to disk at time=21 seconds. Memory usage: 77856768

Writing game id: 730850 to disk at time=21 seconds. Memory usage: 77856768

Writing game id: 558250 to disk at time=22 seconds. Memory usage: 77856768

Writing game id: 674750 to disk at time=22 seconds. Memory usage: 77856768

Writing game id: 695450 to disk at time=22 seconds. Memory usage: 77856768

Writing game id: 682950 to disk at time=22 seconds. Memory usage: 77856768

Writing game id: 706450 to disk at time=24 seconds. Memory usage: 77856768

Writing game id: 546450 to disk at time=24 seconds. Memory usage: 77856768

Writing game id: 575350 to disk at time=24 seconds. Memory usage: 77856768

Writing game id: 616550 to disk at time=25 seconds. Memory usage: 77856768

Writing game id: 648250 to disk at time=26 seconds. Memory usage: 77856768

Writing game id: 763750 to disk at time=25 seconds. Memory usage: 77856768

Writing game id: 613850 to disk at time=26 seconds. Memory usage: 77856768

Writing game id: 645450 to disk at time=25 seconds. Memory usage: 77856768

Writing game id: 695950 to disk at time=33 seconds. Memory usage: 77856768

Writing game id: 661050 to disk at time=27 seconds. Memory usage: 77856768

Writing game id: 461050 to disk at time=27 seconds. Memory usage: 77856768

Writing game id: 693150 to disk at time=29 seconds. Memory usage: 77856768

Thanks!


原文:https://stackoverflow.com/questions/13961322
更新时间:2022-11-26 14:11

最满意答案

我已经尝试过由avo提供的实现 - 但它没有通过所有的测试。 我的意思是它提供了基本的行为,但在更复杂的情况下会失败(如多次投掷,重新夺回等)。

作为Theraot.Core的一部分,我以这样的方式创建了这个类的后端端口,它可以在现代的Mono,旧的Mono(2.6之前的版本)以及2.0到4.0之间的任何Microsoft .NET中工作。

*:用Miguel de Icaza的小技巧:)

下面的代码目前仅在Feature分支上,它最终将移动到主分支(以及.NET 2.0的Task),此时它将通过Theraot.Core nuget提供 。 我将它留在这里以防万一有人需要它。

如果您发现任何问题,欢迎在项目的github(上面链接)上的问题跟踪器上提供错误报告。

#if NET20 || NET30 || NET35 || NET40

using System.Reflection;

namespace System.Runtime.ExceptionServices
{
    /// <summary>
    /// The ExceptionDispatchInfo object stores the stack trace information and Watson information that the exception contains at the point where it is captured. The exception can be thrown at another time and possibly on another thread by calling the ExceptionDispatchInfo.Throw method. The exception is thrown as if it had flowed from the point where it was captured to the point where the Throw method is called.
    /// </summary>
    public sealed class ExceptionDispatchInfo
    {
        private static FieldInfo _remoteStackTraceString;

        private Exception _exception;
        private object _stackTraceOriginal;
        private object _stackTrace;

        private ExceptionDispatchInfo(Exception exception)
        {
            _exception = exception;
            _stackTraceOriginal = _exception.StackTrace;
            _stackTrace = _exception.StackTrace;
            if (_stackTrace != null)
            {
                _stackTrace += Environment.NewLine + "---End of stack trace from previous location where exception was thrown ---" + Environment.NewLine;
            }
            else
            {
                _stackTrace = string.Empty;
            }
        }

        /// <summary>
        /// Creates an ExceptionDispatchInfo object that represents the specified exception at the current point in code.
        /// </summary>
        /// <param name="source">The exception whose state is captured, and which is represented by the returned object.</param>
        /// <returns>An object that represents the specified exception at the current point in code. </returns>
        public static ExceptionDispatchInfo Capture(Exception source)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            return new ExceptionDispatchInfo(source);
        }

        /// <summary>
        /// Gets the exception that is represented by the current instance.
        /// </summary>
        public Exception SourceException
        {
            get
            {
                return _exception;
            }
        }

        private static FieldInfo GetFieldInfo()
        {
            if (_remoteStackTraceString == null)
            {
                // ---
                // Code by Miguel de Icaza

                FieldInfo remoteStackTraceString =
                    typeof(Exception).GetField("_remoteStackTraceString",
                    BindingFlags.Instance | BindingFlags.NonPublic); // MS.Net

                if (remoteStackTraceString == null)
                    remoteStackTraceString = typeof(Exception).GetField("remote_stack_trace",
                        BindingFlags.Instance | BindingFlags.NonPublic); // Mono pre-2.6

                // ---
                _remoteStackTraceString = remoteStackTraceString;
            }
            return _remoteStackTraceString;
        }

        private static void SetStackTrace(Exception exception, object value)
        {
            FieldInfo remoteStackTraceString = GetFieldInfo();
            remoteStackTraceString.SetValue(exception, value);
        }

        /// <summary>
        /// Throws the exception that is represented by the current ExceptionDispatchInfo object, after restoring the state that was saved when the exception was captured.
        /// </summary>
        public void Throw()
        {
            try
            {
                throw _exception;
            }
            catch (Exception exception)
            {
                GC.KeepAlive(exception);
                var newStackTrace = _stackTrace + BuildStackTrace(Environment.StackTrace);
                SetStackTrace(_exception, newStackTrace);
                throw;
            }
        }

        private string BuildStackTrace(string trace)
        {
            var items = trace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
            var newStackTrace = new Text.StringBuilder();
            var found = false;
            foreach (var item in items)
            {
                // Only include lines that has files in the source code
                if (item.Contains(":"))
                {
                    if (item.Contains("System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"))
                    {
                        // Stacktrace from here on will be added by the CLR
                        break;
                    }
                    if (found)
                    {
                        newStackTrace.Append(Environment.NewLine);
                    }
                    found = true;
                    newStackTrace.Append(item);
                }
                else if (found)
                {
                    break;
                }
            }
            var result = newStackTrace.ToString();
            return result;
        }
    }
}

#endif

I have experimented with the implementation provided by avo - yet it doesn't pass all the tests. By that I mean that it provides the basic behaviour but will fail in more complex cases (such as multiple throwing, recapturing, etc...).

As part of Theraot.Core I have made a back port of this class in such way that it will work in modern Mono, old Mono (pre 2.6*) and any Microsoft .NET from 2.0 to 4.0.

*: With a little tip from Miguel de Icaza :)

The code below is currently only on the Feature branch, it will eventually move to the master branch (along with Task for .NET 2.0 :), at which point it will available via the Theraot.Core nuget. I'm leaving it here in case somebody needs it sooner.

Bug reports are welcome on the issue tracker at the project's github (linked above), if you find any.

#if NET20 || NET30 || NET35 || NET40

using System.Reflection;

namespace System.Runtime.ExceptionServices
{
    /// <summary>
    /// The ExceptionDispatchInfo object stores the stack trace information and Watson information that the exception contains at the point where it is captured. The exception can be thrown at another time and possibly on another thread by calling the ExceptionDispatchInfo.Throw method. The exception is thrown as if it had flowed from the point where it was captured to the point where the Throw method is called.
    /// </summary>
    public sealed class ExceptionDispatchInfo
    {
        private static FieldInfo _remoteStackTraceString;

        private Exception _exception;
        private object _stackTraceOriginal;
        private object _stackTrace;

        private ExceptionDispatchInfo(Exception exception)
        {
            _exception = exception;
            _stackTraceOriginal = _exception.StackTrace;
            _stackTrace = _exception.StackTrace;
            if (_stackTrace != null)
            {
                _stackTrace += Environment.NewLine + "---End of stack trace from previous location where exception was thrown ---" + Environment.NewLine;
            }
            else
            {
                _stackTrace = string.Empty;
            }
        }

        /// <summary>
        /// Creates an ExceptionDispatchInfo object that represents the specified exception at the current point in code.
        /// </summary>
        /// <param name="source">The exception whose state is captured, and which is represented by the returned object.</param>
        /// <returns>An object that represents the specified exception at the current point in code. </returns>
        public static ExceptionDispatchInfo Capture(Exception source)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            return new ExceptionDispatchInfo(source);
        }

        /// <summary>
        /// Gets the exception that is represented by the current instance.
        /// </summary>
        public Exception SourceException
        {
            get
            {
                return _exception;
            }
        }

        private static FieldInfo GetFieldInfo()
        {
            if (_remoteStackTraceString == null)
            {
                // ---
                // Code by Miguel de Icaza

                FieldInfo remoteStackTraceString =
                    typeof(Exception).GetField("_remoteStackTraceString",
                    BindingFlags.Instance | BindingFlags.NonPublic); // MS.Net

                if (remoteStackTraceString == null)
                    remoteStackTraceString = typeof(Exception).GetField("remote_stack_trace",
                        BindingFlags.Instance | BindingFlags.NonPublic); // Mono pre-2.6

                // ---
                _remoteStackTraceString = remoteStackTraceString;
            }
            return _remoteStackTraceString;
        }

        private static void SetStackTrace(Exception exception, object value)
        {
            FieldInfo remoteStackTraceString = GetFieldInfo();
            remoteStackTraceString.SetValue(exception, value);
        }

        /// <summary>
        /// Throws the exception that is represented by the current ExceptionDispatchInfo object, after restoring the state that was saved when the exception was captured.
        /// </summary>
        public void Throw()
        {
            try
            {
                throw _exception;
            }
            catch (Exception exception)
            {
                GC.KeepAlive(exception);
                var newStackTrace = _stackTrace + BuildStackTrace(Environment.StackTrace);
                SetStackTrace(_exception, newStackTrace);
                throw;
            }
        }

        private string BuildStackTrace(string trace)
        {
            var items = trace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
            var newStackTrace = new Text.StringBuilder();
            var found = false;
            foreach (var item in items)
            {
                // Only include lines that has files in the source code
                if (item.Contains(":"))
                {
                    if (item.Contains("System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"))
                    {
                        // Stacktrace from here on will be added by the CLR
                        break;
                    }
                    if (found)
                    {
                        newStackTrace.Append(Environment.NewLine);
                    }
                    found = true;
                    newStackTrace.Append(item);
                }
                else if (found)
                {
                    break;
                }
            }
            var result = newStackTrace.ToString();
            return result;
        }
    }
}

#endif

相关问答

更多

相关文章

更多

最新问答

更多
  • 您如何使用git diff文件,并将其应用于同一存储库的副本的本地分支?(How do you take a git diff file, and apply it to a local branch that is a copy of the same repository?)
  • 将长浮点值剪切为2个小数点并复制到字符数组(Cut Long Float Value to 2 decimal points and copy to Character Array)
  • OctoberCMS侧边栏不呈现(OctoberCMS Sidebar not rendering)
  • 页面加载后对象是否有资格进行垃圾回收?(Are objects eligible for garbage collection after the page loads?)
  • codeigniter中的语言不能按预期工作(language in codeigniter doesn' t work as expected)
  • 在计算机拍照在哪里进入
  • 使用cin.get()从c ++中的输入流中丢弃不需要的字符(Using cin.get() to discard unwanted characters from the input stream in c++)
  • No for循环将在for循环中运行。(No for loop will run inside for loop. Testing for primes)
  • 单页应用程序:页面重新加载(Single Page Application: page reload)
  • 在循环中选择具有相似模式的列名称(Selecting Column Name With Similar Pattern in a Loop)
  • System.StackOverflow错误(System.StackOverflow error)
  • KnockoutJS未在嵌套模板上应用beforeRemove和afterAdd(KnockoutJS not applying beforeRemove and afterAdd on nested templates)
  • 散列包括方法和/或嵌套属性(Hash include methods and/or nested attributes)
  • android - 如何避免使用Samsung RFS文件系统延迟/冻结?(android - how to avoid lag/freezes with Samsung RFS filesystem?)
  • TensorFlow:基于索引列表创建新张量(TensorFlow: Create a new tensor based on list of indices)
  • 企业安全培训的各项内容
  • 错误:RPC失败;(error: RPC failed; curl transfer closed with outstanding read data remaining)
  • C#类名中允许哪些字符?(What characters are allowed in C# class name?)
  • NumPy:将int64值存储在np.array中并使用dtype float64并将其转换回整数是否安全?(NumPy: Is it safe to store an int64 value in an np.array with dtype float64 and later convert it back to integer?)
  • 注销后如何隐藏导航portlet?(How to hide navigation portlet after logout?)
  • 将多个行和可变行移动到列(moving multiple and variable rows to columns)
  • 提交表单时忽略基础href,而不使用Javascript(ignore base href when submitting form, without using Javascript)
  • 对setOnInfoWindowClickListener的意图(Intent on setOnInfoWindowClickListener)
  • Angular $资源不会改变方法(Angular $resource doesn't change method)
  • 在Angular 5中不是一个函数(is not a function in Angular 5)
  • 如何配置Composite C1以将.m和桌面作为同一站点提供服务(How to configure Composite C1 to serve .m and desktop as the same site)
  • 不适用:悬停在悬停时:在元素之前[复制](Don't apply :hover when hovering on :before element [duplicate])
  • 常见的python rpc和cli接口(Common python rpc and cli interface)
  • Mysql DB单个字段匹配多个其他字段(Mysql DB single field matching to multiple other fields)
  • 产品页面上的Magento Up出售对齐问题(Magento Up sell alignment issue on the products page)