- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
看来 Hệ thống.Bộ đếm thời gian.Bộ đếm thời gian
实例通过某种机制保持事件状态,但 Hệ thống.Threading.Timer
实例则不然。
示例程序,具有定期Hệ thống.Threading.Timer
和自动重置Hệ thống.Bộ đếm thời gian.Bộ đếm thời gian
:
class Program
{
void tĩnh Main(string[] args)
{
var timer1 = new System.Threading.Timer(
_ => Console.WriteLine("Stayin alive (1)..."),
null,
0,
400);
var timer2 = new System.Timers.Timer
{
Interval = 400,
AutoReset = true
};
timer2.Elapsed += (_, __) => Console.WriteLine("Stayin alive (2)...");
timer2.Enabled = true;
System.Threading.Thread.Sleep(2000);
Console.WriteLine("Invoking GC.Collect...");
GC.Collect();
Console.ReadKey();
}
}
当我运行此程序(.NET 4.0 客户端、Release、调试器外部)时,只有 Hệ thống.Threading.Timer
被 GC 处理:
Stayin alive (1)...
Stayin alive (1)...
Stayin alive (2)...
Stayin alive (1)...
Stayin alive (2)...
Stayin alive (1)...
Stayin alive (2)...
Stayin alive (1)...
Stayin alive (2)...
Invoking GC.Collect...
Stayin alive (2)...
Stayin alive (2)...
Stayin alive (2)...
Stayin alive (2)...
Stayin alive (2)...
Stayin alive (2)...
Stayin alive (2)...
Stayin alive (2)...
Stayin alive (2)...
biên tập:我已经接受了下面约翰的回答,但我想稍微解释一下。
运行上面的示例程序时(在 Sleep
处设置断点),以下是相关对象和 GCHandle
表的状态:
!dso
OS Thread Id: 0x838 (2104)
ESP/REG Object Name
0012F03C 00c2bee4 System.Object[] (System.String[])
0012F040 00c2bfb0 System.Timers.Timer
0012F17C 00c2bee4 System.Object[] (System.String[])
0012F184 00c2c034 System.Threading.Timer
0012F3A8 00c2bf30 System.Threading.TimerCallback
0012F3AC 00c2c008 System.Timers.ElapsedEventHandler
0012F3BC 00c2bfb0 System.Timers.Timer
0012F3C0 00c2bfb0 System.Timers.Timer
0012F3C4 00c2bfb0 System.Timers.Timer
0012F3C8 00c2bf50 System.Threading.Timer
0012F3CC 00c2bfb0 System.Timers.Timer
0012F3D0 00c2bfb0 System.Timers.Timer
0012F3D4 00c2bf50 System.Threading.Timer
0012F3D8 00c2bee4 System.Object[] (System.String[])
0012F4C4 00c2bee4 System.Object[] (System.String[])
0012F66C 00c2bee4 System.Object[] (System.String[])
0012F6A0 00c2bee4 System.Object[] (System.String[])
!gcroot -nostacks 00c2bf50
!gcroot -nostacks 00c2c034
DOMAIN(0015DC38):HANDLE(Strong):9911c0:Root: 00c2c05c(System.Threading._TimerCallback)->
00c2bfe8(System.Threading.TimerCallback)->
00c2bfb0(System.Timers.Timer)->
00c2c034(System.Threading.Timer)
!gchandles
GC Handle Statistics:
Strong Handles: 22
Pinned Handles: 5
Async Pinned Handles: 0
Ref Count Handles: 0
Weak Long Handles: 0
Weak Short Handles: 0
Other Handles: 0
Statistics:
MT Count TotalSize Class Name
7aa132b4 1 12 System.Diagnostics.TraceListenerCollection
79b9f720 1 12 System.Object
79ba1c50 1 28 System.SharedStatics
79ba37a8 1 36 System.Security.PermissionSet
79baa940 2 40 System.Threading._TimerCallback
79b9ff20 1 84 System.ExecutionEngineException
79b9fed4 1 84 System.StackOverflowException
79b9fe88 1 84 System.OutOfMemoryException
79b9fd44 1 84 System.Exception
7aa131b0 2 96 System.Diagnostics.DefaultTraceListener
79ba1000 1 112 System.AppDomain
79ba0104 3 144 System.Threading.Thread
79b9ff6c 2 168 System.Threading.ThreadAbortException
79b56d60 9 17128 System.Object[]
Total 27 objects
正如 John 在他的回答中指出的那样,两个计时器都在 GCHandle
表中注册了它们的回调 (System.Threading._TimerCallback
)。正如 Hans 在评论中指出的那样,完成此操作后,state
参数也保持事件状态。
正如 John 指出的,Hệ thống.Bộ đếm thời gian.Bộ đếm thời gian
保持事件状态是因为它被回调引用(它作为 state
参数传递给内部Hệ thống.Threading.Timer
);同样,我们的 System.Threading.Timer 被 GC 回收的原因是因为它的回调没有引用它。
添加对 timer1
回调的显式引用(例如,Console.WriteLine("Stayin alive ("+ timer1.GetType().FullName + ")")
) 足以防止 GC。
hiện hữuHệ thống.Threading.Timer
上使用单参数构造函数也可以,因为计时器将引用自身作为state
参数。以下代码在 GC 之后使两个计时器保持事件状态,因为它们均由 GCHandle
表中的回调引用:
class Program
{
void tĩnh Main(string[] args)
{
System.Threading.Timer timer1 = null;
timer1 = new System.Threading.Timer(_ => Console.WriteLine("Stayin alive (1)..."));
timer1.Change(0, 400);
var timer2 = new System.Timers.Timer
{
Interval = 400,
AutoReset = true
};
timer2.Elapsed += (_, __) => Console.WriteLine("Stayin alive (2)...");
timer2.Enabled = true;
System.Threading.Thread.Sleep(2000);
Console.WriteLine("Invoking GC.Collect...");
GC.Collect();
Console.ReadKey();
}
}
1 Câu trả lời
您可以使用 Windbg、sos 和 !gcroot
回答此问题及类似问题。
0:008> !gcroot -nostacks 0000000002354160
DOMAIN(00000000002FE6A0):HANDLE(Strong):241320:Root:00000000023541a8(System.Thre
ading._TimerCallback)->
00000000023540c8(System.Threading.TimerCallback)->
0000000002354050(System.Timers.Timer)->
0000000002354160(System.Threading.Timer)
0:008>
在这两种情况下, native 计时器都必须阻止回调对象的 GC(通过 GCHandle)。不同之处在于 Hệ thống.Bộ đếm thời gian.Bộ đếm thời gian
的情况回调引用 Hệ thống.Bộ đếm thời gian.Bộ đếm thời gian
对象(使用 Hệ thống.Threading.Timer
在内部实现)
关于.net - 为什么 System.Timers.Timer 能在 GC 中幸存下来,而 System.Threading.Timer 却不能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4962172/
Cách tốt nhất để thực hiện nhiệm vụ này là gì: Luồng chính (luồng A) tạo ra hai luồng khác (luồng B và luồng C). Luồng B và C thực hiện I/O đĩa nặng và cuối cùng cần chuyển các tài nguyên mà chúng tạo ra cho luồng A, sau đó luồng A sẽ gọi tệp DLL bên ngoài
Tôi là một lập trình viên mới và quan tâm đến ngôn ngữ Julia. Tài liệu (https://docs.julialang.org/en/v1/base/multi-threading/) ghi là Threads.@thread
Sự khác biệt giữa thread.start_new_thread và threading.Thread.start trong Python là gì? Tôi nhận thấy rằng khi start_new_thread được gọi, luồng mới sẽ bị chấm dứt khi luồng gọi
Tôi đang học lập trình Android Bluetooth. Tôi đã sao chép hầu hết mã từ trang web Android Developers của Google cho mục đích học tập. Ý tưởng là việc lắng nghe các kết nối trên máy chủ được thực hiện trong một luồng mới mà không chặn luồng UI. Khi nhận được yêu cầu kết nối, kết nối
Luồng thực thi phương thức của đối tượng có phụ thuộc vào luồng mà nó được tạo ra không? Giả sử bạn có hai luồng Thread1 và Thread2 và hai lớp ClassA và ClassB trong ứng dụng Java của bạn. Bạn đang ở Chủ đề 1
Tôi đang thử nghiệm luồng C++11 bằng mã này, nhưng khi tạo luồng, tôi nhận được lỗi không có hàm phù hợp để gọi đến 'std::thread::thread()'. Giống như có gì đó không ổn với lệnh ctr mà tôi đưa cho hàm std::thread.
Tôi có lớp eventEngine và gateway sau: class eventEngine { public: eventEngine(); std::thread threa; std
Tôi cần chạy nhiều luồng của lớp Observer bằng số phần tử trong danh sách dirlist. Khi tôi chạy lệnh python console thì nó hoạt động tốt. lớp Observer(Thread): def ru
Tôi đọc được đoạn mã sau trong một cuốn sách Java. Tôi biết rằng lớp Main kế thừa lớp Thread theo mặc định, do đó currentThread(); thay vì Thread.currentThread(); cũng sẽ thực hiện được công việc này. Nhưng tôi không hiểu
Tôi đang sử dụng API của bên thứ 3 trong hệ thống của mình để khởi động một luồng người dùng chạy mãi mãi. Sau khi chương trình của tôi kết thúc, JVM tiếp tục chạy vì luồng này, vì vậy tôi thử lấy tham chiếu luồng này và thay đổi nó bằng thread.setDaemon(t
Mọi đối tượng trong Python mà tôi biết đều xử lý việc khởi tạo lớp cơ sở của nó bằng cách gọi: super(BaseClass, self).__init__() Điều này có vẻ không đúng với các lớp con của threading.Thread ,
Trong một dự án Xamarin mà tôi mới làm gần đây, tôi thấy rằng nhà phát triển đã sử dụng Java.Lang.Thread cũng như System.Threading.Thread (cho các hoạt động rất giống nhau - như tải dữ liệu ở chế độ nền).
Tôi đang chạy một vòng kép trong Julia. Mã này rất đơn giản. w = rand(1000,1000) hàm regular_demo(w::Array{Float64, 2}) n = kích thước
Tôi đang sử dụng Python 3 trên Windows. Tôi đang sử dụng threading.Thread để chạy một hàm một cách động và tôi có thể gọi nó có hoặc không có đối số. Tôi đang thiết lập một danh sách trong đó mục đầu tiên là một chuỗi xác định đường dẫn. Các thông số khác
Tôi đã tìm thấy một số ví dụ về việc quản lý luồng bằng cách sử dụng mô-đun luồng (sử dụng Python 2.6). Điều tôi muốn hiểu là phương thức "Run" được gọi như thế nào và ở đâu trong ví dụ này. Tôi không thấy nó ở đâu cả. Lớp ThreadUrl trong hàm main()
Giả sử tôi bắt nguồn từ threading.Thread: from threading import Thread class Worker(Thread): def start(self):
đóng cửa. Câu hỏi này cần thông tin gỡ lỗi. Hiện tại không chấp nhận câu trả lời. Chỉnh sửa câu hỏi để bao gồm hành vi mong muốn, một vấn đề hoặc lỗi cụ thể và
Sử dụng WinDbg và SOS, tôi có những thông tin sau: 0:011> !threads ThreadCount: 7 UnstartedThread: 0 BackgroundThread: 4 Pendin
App Engine đưa ra lỗi: com.google.apphosting.api.ApiProxy$CallNotFoundException: Không thể thực hiện lệnh gọi API urlfe
Tôi đang cố nhúng Swing JEditorPane vào một dự án JavaFX như được hiển thị trong đoạn mã sau. Platform.runLater(() -> { SyntaxTester ob = mới
Tôi là một lập trình viên xuất sắc, rất giỏi!