- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试构建一个服务器。除了像普通服务器一样接受来自客户端的连接,我的服务器也会作为客户端连接其他服务器。
我已经像下面这样设置了协议(protocol)和端点:
p = FooProtocol()
client = TCP4ClientEndpoint(reactor, '127.0.0.1' , 8080) # without ClientFactory
然后,在调用 reactor.run()
之后,服务器将监听/接受新的套接字连接。当建立新的套接字连接时(在 connectionMade 中),服务器将调用 connectProtocol(client, p)
,其行为类似于以下伪代码:
while server accept new socket:
connectProtocol(client, p)
# client.client.connect(foo_client_factory) --> connecting in this way won't
# cause memory leak
随着与客户端的连接建立,内存逐渐消耗(显式调用gc
不起作用)。
我是否以错误的方式使用了 Twisted?
-----更新-----
我的测试程序:服务器等待客户端连接。当客户端建立连接时,服务器将创建 50 个到其他服务器的连接
代码如下:
#! /usr/bin/env python
import sys
import gc
from twisted.internet import protocol, reactor, defer, endpoints
from twisted.internet.endpoints import TCP4ClientEndpoint, connectProtocol
class MyClientProtocol(protocol.Protocol):
def connectionMade(self):
self.transport.loseConnection()
class MyClientFactory(protocol.ClientFactory):
def buildProtocol(self, addr):
p = MyClientProtocol()
return p
class ServerFactory(protocol.Factory):
def buildProtocol(self, addr):
p = ServerProtocol()
return p
client_factory = MyClientFactory() # global
client_endpoint = TCP4ClientEndpoint(reactor, '127.0.0.1' , 8080) # global
times = 0
class ServerProtocol(protocol.Protocol):
def connectionMade(self):
global client_factory
global client_endpoint
global times
for i in range(50):
# 1)
p = MyClientProtocol()
connectProtocol(client_endpoint, p) # cause memleak
# 2)
#client_endpoint.connect(client_factory) # no memleak
times += 1
if times % 10 == 9:
print 'gc'
gc.collect() # doesn't work
self.transport.loseConnection()
if __name__ == '__main__':
server_factory = ServerFactory()
serverEndpoint = endpoints.serverFromString(reactor, "tcp:8888")
serverEndpoint.listen(server_factory)
reactor.run()
最佳答案
这个程序不做任何 Twisted 日志初始化。这意味着它在整个运行过程中都以“日志初学者”运行。日志初学者记录它在 LimitedHistoryLogObserver
中观察到的所有日志事件(达到可配置的最大值)。
日志初学者保留 2 ** 16 (_DEFAULT_BUFFER_MAXIMUM
) 个事件,然后开始丢弃旧的,大概是为了避免在一个程序从不配置另一个程序时消耗所有可用内存观察员。
如果您破解 Twisted 源代码以将 _DEFAULT_BUFFER_MAXIMUM
设置为较小的值(例如 10),那么程序将不再“泄漏”。当然,这实际上只是一个对象泄漏,而不是内存泄漏,并且它受到 Twisted 强加的 2 ** 16 限制的限制。
但是,connectProtocol
每次被调用时都会创建一个新工厂。创建每个新工厂时,它都会记录一条消息。并且应用程序代码为每条日志消息生成一个新的 Logger
。 并且 日志记录代码将新的Logger
放入 日志消息中。这意味着保留这些日志消息的内存成本非常明显(与仅泄漏一小段文本或什至泄漏其中包含一些简单对象的字典相比)。
我会说 Twisted 中的代码的行为符合预期……但也许有人没有完整地考虑该行为的后果。
而且,当然,如果您配置自己的日志观察器,那么“日志初学者”就被排除在外并且没有问题。期望所有严肃的程序都能相当快地启用日志记录并避免这个问题似乎是合理的。但是,许多短的一次性程序或示例程序通常不会初始化日志记录,而是依赖于打印,从而使它们受到这种行为的影响。
关于python - Twisted:使用 connectProtocol 连接端点导致内存泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40604545/
我正在尝试构建一个服务器。除了像普通服务器一样接受来自客户端的连接,我的服务器也会作为客户端连接其他服务器。 我已经像下面这样设置了协议(protocol)和端点: p = FooProtocol()
我是一名优秀的程序员,十分优秀!