我有一个Perl项目,我通过打一个循环包调用问题.下面的代码演示了这个问题.
执行此操作时,每个程序包将调用另一个程序包,直到计算机的所有内存都被占用并锁定.我同意这是一个糟糕的设计,这样的循环调用不应该在设计中进行,但我的项目足够大,我想在运行时检测到这一点.
我已经阅读了弱化函数和Data :: Structure :: Util,但我还没有找到一种方法来检测是否存在循环包加载(我假设,因为在每次迭代时都会生成一个新副本并存储在$ this hash的每个副本中).有任何想法吗?
use system::one;
my $one = new system::one();
package system::one;
use strict;
use system::two;
sub new {
my ($class) = @_;
my $this = {};
bless($this,$class);
# attributes
$this->{two} = new system::two();
return $this;
}
package system::two;
use strict;
use system::one;
sub new {
my ($class) = @_;
my $this = {};
bless($this,$class);
# attributes
$this->{one} = new system::one();
return $this;
}
Run Code Online (Sandbox Code Playgroud) 我知道您可能已经厌倦了再次回答相同的问题,但我仍然在其他几个 问题中讨论了错误:
承诺已经在评估中:递归默认参数引用还是早期问题?
即使我确实遵循了前期的"繁琐"建议".":
show.large.objects.threshold <- 100000
show.large.objects.exclude <- c("closure")
show.large.objects <- function (.envir = sys.frame(),
threshold = show.large.objects.threshold,
exclude = show.large.objects.exclude) {
for (n in print(ls(.envir, all.names = TRUE))) tryCatch({
o <- get(n,envir = .envir)
s <- object.size(o)
if (s > threshold && !(typeof(o) %in% exclude)) {
cat(n,": ")
print(s,units="auto")
}
}, error = function(e) { cat("n=",n,"\n"); print(e) })
}
show.large.objects.stack <- function (.threshold = show.large.objects.threshold,
skip.levels = 1,# do not examine the last …Run Code Online (Sandbox Code Playgroud) 在 C++ 程序执行期间,特定函数的堆栈帧是否始终具有恒定大小,或者在某些情况下允许编译器进行动态堆栈管理,类似于 alloca() 函数的作用?为了更好地描述它,我的意思是堆栈帧中特定局部变量或对象的偏移量可能会在函数的不同执行时发生变化
在x86汇编语言中:
我假设我有一个正常的功能序言,请阅读
push ebp
mov ebp,esp
Run Code Online (Sandbox Code Playgroud)
我知道我可以通过访问内存目标操作数来读取或写入寄存器,假设我想要第一个参数。我会做
mov eax,[ebp +8]
Run Code Online (Sandbox Code Playgroud)
从堆栈中获取一个整数参数。
那为什么我不直接使用stackpointer呢?
add esp,8 ; point ESP at the data we want
pop eax
sub esp,12 ; restore ESP to its original position
Run Code Online (Sandbox Code Playgroud)
这会导致错误吗?在任何情况下都使用吗?
我当然知道第一个操作的大小较小,因为它只是一个操作码,mov而不是三个,但这不是问题的重点。
(编者注:mov eax, [ebp+8]。在x86机器代码的3字节的指令 add/ subESP,imm8指定为3个字节的每个,pop eax是1个字节。
mov eax, [esp+8]是一个4字节的指令:不像在16位寻址模式,ESP可以是一个基址寄存器。但是它确实需要一个SIB字节来对其进行编码。
这些都是现代CPU上的单联指令,不包括额外的堆栈同步联指令。)
为什么这样做是错误的做法?
背景信息:我有一个函数可以直接或通过其他函数间接调用自身,并且希望有一种廉价的方法可以在程序耗尽调用堆栈时优雅地失败。我可以手动计算呼叫数,但我想要一种更优雅、更强大的方式来实现这一点。
是否可以使用稳定的 Rust 确定当前的调用堆栈深度?
我能找到的唯一选择是:
我正在尝试展平一个由 100 000 个项目组成的巨大数组,我将其展平两次,因为它是二维的,我想获取第二个数组内的所有对象:
[ [ {} ] ]
我尝试过使用reduce和concat,如下所示:
连接。firstFlat 会在一秒内处理完毕。SecondFlat 会导致超出最大调用堆栈。
let firstArray = Array(100000).fill(Array(7).fill({}));
let firstFlat = [].concat.apply([], firstArray);
let secondFlat = [].concat.apply([], firstFlat);
Run Code Online (Sandbox Code Playgroud)
减少。调用栈也超出了
let array = Array(100000).fill(Array(7).fill({}))
.reduce((x, y) => x.concat(y))
.reduce((x, y) => x.concat(y))
.reduce((x, y) => x.concat(y));
Run Code Online (Sandbox Code Playgroud)
我想不出解决方案,可能是因为我不太了解调用堆栈到底是什么。我知道它是当前正在执行的所有函数的“堆栈”。但reduce不应该只有1个函数吗?并且里面的匿名函数执行一次,然后匿名函数与其他参数一起使用。所以调用堆栈上应该有1个reduce函数和1个匿名函数。那么如何超出调用堆栈呢?我能想到的唯一原因是reduce是一个函数循环,我不知道如何调用它,但就像我的意思是这样的:function a() { a() },它可能就是这样。在这种情况下,我最好使用 forEach/for。但是为什么第一个方法超出了调用堆栈呢?Concat 也只是一个函数,对吗?我很困惑。
我真的很感激一些帮助!提前致谢
编辑:Object.assign 似乎也发生同样的问题。所有这些函数都依赖于函数循环。我认为应该更新,所以他们使用异步等待,这样调用堆栈就不会填满
我正在开发 TypeScript 调试工具,但遇到了似乎无法以编程方式访问 TypeScript 调用堆栈的问题。
当我这样做时:
const error = new Error();
console.log(error.stack);
Run Code Online (Sandbox Code Playgroud)
我得到了预期的结果,并且可以看到 TypeScript 调用堆栈。
但如果我这样做:
const error = new Error();
const errorStack = error.stack;
console.log(errorStack);
Run Code Online (Sandbox Code Playgroud)
我只得到 JavaScript 堆栈,而不是预期的 TypeScript 堆栈。
问题在于如何或何时应用源映射。
有没有办法将第一个示例中作为控制台输出获得的相同信息获取到 TypeScript/JavaScript 变量中?任何帮助是极大的赞赏!
在由 生成perf record --call-graph dwarf和打印的回溯中perf script,我一直得到可能有 5% 的调用堆栈的错误地址,即展开失败。一个例子是
my_bin 770395 705462.825887: 3560360 cycles:
7f0398b9b7e2 __vsnprintf_internal+0x12 (/usr/lib/x86_64-linux-gnu/libc-2.32.so)
7ffcdb6fbfdf [unknown] ([stack])
my_bin 770395 705462.827040: 3447195 cycles:
7f0398ba1624 __GI__IO_default_xsputn+0x104 (inlined)
7ffcdb6fb7af [unknown] ([stack])
Run Code Online (Sandbox Code Playgroud)
它是从此代码生成的(使用 编译g++ -O3 -g -fno-omit-frame-pointer my_bin.cpp -o my_bin):
#include <cstdio>
#include <iostream>
int __attribute__ ((noinline)) libc_string(int x) {
char buf[64] = {0};
// Some nonsense workload using libc
int res = 0;
for (int i = 0; i < x; ++i) {
res += …Run Code Online (Sandbox Code Playgroud) 就我而言,以下代码将在堆栈上创建一个数组:
unsafe struct Foo
{
public fixed int bar[10];
}
var foo = new Foo();
Run Code Online (Sandbox Code Playgroud)
stackalloc 语句会做同样的事情:
public void unsafe foo(int length)
{
Span<int> bar = stackalloc int[length];
}
Run Code Online (Sandbox Code Playgroud)
所以我想知道这些方法之间有什么区别。固定大小缓冲区的目的是什么?每个人都在谈论性能提升,但我不明白为什么我需要它们,当我已经可以使用 stackalloc 在堆栈上创建数组时。MSDN 表示固定大小的缓冲区用于与其他平台“互操作”。那么这个“互操作”是什么样的呢?
当鼠标触发单击事件时,它的行为符合预期:
首先,侦听器 1 被推入堆栈,并在微任务队列(或作业队列)中对 Promise 1 进行排队。当侦听器 1 弹出时,堆栈变空。Promise 1 回调在侦听器 2 之前执行(侦听器 2 在任务队列(或回调队列)中等待)。在 Promise 1 回调弹出后,侦听器 2 被压入堆栈。因此输出为:
侦听器 1 微任务 1 侦听器 2 微任务 2
但是,当通过 JavaScript 代码触发点击时,其行为会有所不同:
即使在 click() 函数完成之前,回调也会被推入堆栈(即调用堆栈不为空)。这里的输出是:
监听器 1 监听器 2 微任务 1 微任务 2
这是代码:
window.onload = function(){
document.getElementById("myBtn").addEventListener('click', () => {
Promise.resolve().then(() => console.log('Microtask 1'));
console.log('Listener 1');
} );
document.getElementById("myBtn").addEventListener('click', () => {
Promise.resolve().then(() => console.log('Microtask 2'));
console.log('Listener 2');
} );
}
function clickB(){
document.getElementById("myBtn").click();
}Run Code Online (Sandbox Code Playgroud)
<!DOCTYPE html>
<html>
<button id="myBtn">Manual …Run Code Online (Sandbox Code Playgroud)callstack ×10
c++ ×2
javascript ×2
recursion ×2
abi ×1
arrays ×1
assembly ×1
backtrace ×1
c# ×1
console.log ×1
dom-events ×1
dwarf ×1
event-loop ×1
function ×1
object ×1
packages ×1
perf ×1
performance ×1
perl ×1
r ×1
red-zone ×1
rust ×1
size ×1
typescript ×1
x86 ×1