后退——回到C++时间

后退C++

在最近的15.9更新VisualStudio 2017企业版中,我们为C++开发人员添加了“步骤后退”,针对Windows 10周年纪念更新(1607)和以后。使用此功能,您现在可以在调试时返回到以前的状态,而无需重新启动整个进程。它是作为C++工作负载的一部分安装的,但默认情况下设置为“off”。要启用它,请转到“工具”->“选项”->“IntelliTrace”,然后选择“IntelliTrace快照”选项。这将为托管代码和本机代码启用快照。

null

图片[1]-后退——回到C++时间-yiteyi-C++库

一旦启用“步退”,您将看到当您正在通过C++代码时,在诊断工具窗口的事件选项卡中出现快照。 图片[2]-后退——回到C++时间-yiteyi-C++库 点击任何一个事件都会带你回到它各自的快照——如果你想比几步走得更远的话,这是一种更有效的回到时间的方式。或者,您可以简单地使用调试命令栏上的“后退”按钮返回时间。您可以在下面的gif中看到“Step Back”与“Step Over”同时运行。

图片[3]-后退——回到C++时间-yiteyi-C++库

在引擎盖下

到目前为止,我们已经讨论了“后退”以及如何在visualstudio中启用和使用它,但是您可以在 VS博客 . 在VC++的博客上,我想解释一下这个特性是如何工作的以及它们之间的取舍是什么是很有趣的。毕竟,没有软件,包括调试器,是神奇的!

“退一步”的核心是Windows中一个名为 PSCaptureSnapshot(捕获快照) ( 文件 ). 虽然API不是很具描述性,但它对流程有两个关键作用。给定一个目标流程,它将:

  1. 创建一个“快照”,它看起来可疑地像没有线程运行的现有进程的子进程。
  2. 标记进程内存,它是页表( 维基百科 ),作为写入时复制( 维基百科 ). 这意味着无论何时写入表,都会复制该表。

上面提到的重要一点是,在这两者之间,基本上可以得到快照进程所使用的整个虚拟内存空间的副本。然后,您可以从该进程内部检查应用程序的状态、内存以及创建快照时的状态。这对于API最初设计的特性来说是很方便的;在失败点对进程的序列化。

在调试C++时,我们在某些调试器事件上使用这些快照,即:

  1. 当遇到断点时
  2. 当一个步进事件发生时-但仅当步进动作和前一步进动作之间的时间高于某个阈值(约300ms)。这有助于您敲打步进按钮的情况下,只是想在所有可能的速度步。

从实际的角度来看,这意味着在逐步完成代码时会有一个快照。我们保留了一个先进先出的快照缓冲区,当更多的快照被拍摄时释放它们。这种方法的缺点之一是,我们不会在你的应用程序运行时拍摄快照,这样你就不能命中断点,然后返回查看在命中断点之前发生了什么。

现在有一个进程的副本,一个快照,但是如何在VS中调试它呢?

好吧,这是“简单”的一点,基本上当你点击“后退”或从Diagnostic Tools窗口激活快照时,VS继续并将调试器附加到该进程。我们在vsui中对您隐藏了这一点,因此看起来您仍然在调试开始的进程,但实际上,您正在调试快照进程,使用的是过去的所有状态。一旦您返回到“实时”调试,您将返回到主进程,它仍然在您离开它的位置暂停。

退后表演

向调试器添加任何新功能的首要考虑之一是它在调试时如何影响VS的性能。虽然提高VS的性能是一个西西弗斯的任务和许多改进,因为我们做了更多的是要做的,以及额外的功能,采取一些这些胜利。拍摄快照需要时间,所有事情都需要时间,在这种情况下,无论是在调试过程中还是在VS中,都需要时间。由于快照依赖于应用程序以及如何使用内存,因此无法确定需要多长时间,但虽然我们没有神奇的8球,但我们确实有数据,很多数据…

截至本文撰写之时,从过去28天的测试和dogfooding使用情况来看,我们已经看到了在14738台机器上拍摄的29635121张快照。从这个数据集中我们可以看到,拍摄快照所用时间的第75个百分位是81毫秒。您可以在下面的图表中看到更详细的细分。

图片[4]-后退——回到C++时间-yiteyi-C++库 在任何情况下,如果您想知道为什么“Step Back”在默认情况下不启用,那么上面的图表就是为什么“Step Back”对Step性能的影响太大了,以至于在默认情况下,对每个人来说都不会一直启用。相反,它是一个你应该决定使用的工具,总的来说,你可能永远不会注意到它的影响。不过,如果您这样做了,我们将关闭“后退”,并显示“金条”通知,说明我们已经这样做了。“金条”是在编辑器顶部弹出的通知,下图显示了在不启用快照的情况下尝试“后退”时的通知。 图片[5]-后退——回到C++时间-yiteyi-C++库 这就是性能的CPU使用方面,现在来看第二个方面,内存。

当你继续调试你的应用程序和应用程序继续执行它无疑将写入内存。这可以是将值从1设置为2,如上面的示例所示。或者它可能是更复杂的东西,但是在任何情况下,当需要编写更改时,操作系统将把关联的页表复制到一个新位置。在新位置复制已更改的数据和其他潜在数据,同时保留旧数据。这个新地点将继续使用。这意味着从拍摄快照时起,旧位置仍具有旧值1,而新位置的值为2。由于Windows正在复制写入时的内存,应用程序将消耗更多内存。但这要取决于应用程序和它在做什么。内存的消耗与它的易失性成正比。例如,在上面这个微不足道的应用程序中,每一步都会消耗更多的数据。但是,如果应用程序改为编码图像或做一些高强度的事情,那么消耗的内存将比通常情况下多得多。

现在,由于内存,甚至是虚拟内存,是有限的,这对后退造成了一些限制。也就是说,我们不能保持无限数量的快照。在某个时刻,我们必须释放它们和它们相关的内存。我们通过两种方式来实现这一点;首先,一旦达到100的限制,快照将以先进先出的方式释放。也就是说,你不能后退超过100倍。这个上限是任意的,一个神奇的数字。有一个额外的上限是强制执行的,基于启发式,本质上VS是观察内存使用情况,在内存不足的情况下,快照会从最旧的快照开始删除,就像命中了100一样。

结论

我们已经介绍了如何使用“退后一步”以及它是如何在引擎盖下工作的,希望您现在能够对何时使用该功能做出明智的决定。虽然此功能仅在VisualStudio的企业版中提供,但您始终可以尝试 预览频道 Visual Studio企业版。我强烈建议你去打开它,对我个人来说,它节省了大量的时间不重新启动调试会话。当你使用这个功能的时候,我很想听听你的反馈,如果你对VS中的调试器体验有任何反馈,请告诉我们!

你也可以邮寄到 andster@microsoft.com )或者在twitter上 https://twitter.com/andysterland .

感谢阅读!

安迪·斯特兰

程序经理,Visual Studio,诊断团队

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享