Project1

标题: 新人初到,写了一些小脚本,问些问题,谢谢!!! [打印本页]

作者: 3694260ac    时间: 2008-5-17 01:19
标题: 新人初到,写了一些小脚本,问些问题,谢谢!!!
前天下午看了一些RMXP自带脚本,花了2个晚上写了一些小脚本,实现了人物地图上移动以及地图切换的功能,出了点挺严重的问题,在这儿问问,谢谢!!!!!!!!!!

程序地点:
http://rpg.blue/upload_program/files/Project2_91388222.rar

其中一些map_data的TXT是地图信息的

主要问题:
1.随人物行走内存占用逐渐变大,换图后尤其明显,而且不会下降
2.Graphic和Input的工作方式
3.有关类的内存释放

之后还有一个小脚本有问题:
class Map
  def initialize
    @devil = Sprite.new
    @devil.bitmap = Bitmap.new("Graphics/Battlers/075-Devil01")
    @devil.ox = -100
    @devil.oy = -100
    @num = 1000
  end
  def input
    if Input.press?(Input::DOWN)
      @devil.oy -= 1
      refresh
    end
    if Input.press?(Input::UP)
      @devil.oy += 1
      refresh
    end
    if Input.press?(Input::LEFT)
      @devil.ox -= 1
      refresh
    end
    if Input.press?(Input::RIGHT)
      @devil.ox += 1
      refresh
    end
  end
  def refresh
    for i in 0...@num
    end
  end
end
@map = Map.new
loop do
  Graphics.update
  @map.input
  Input.update
end
运行之后按方向建可以看到内存占用在变大,请问是其中的哪些部分不断申请的?


希望有人能给出解答,非常感谢!!!!!!!!!!!!!

作者: 3694260ac    时间: 2008-5-17 01:21
自杀下!!!!!!!!!!!!!!!!! [LINE]1,#dddddd[/LINE]版主对此帖的评论:『连帖』,积分『-5』。这些被扣积分的一半会用于对本帖正确答案的悬赏。
作者: 3694260ac    时间: 2008-5-17 01:37
之前程序有点错误,已经改了,请重新下载
作者: 美兽    时间: 2008-5-17 01:59
   for i in 0...@num
   end

作者: 3694260ac    时间: 2008-5-17 02:08
它是怎样申请的?
能否释放?
作者: cZooCz    时间: 2008-5-17 02:49
LZ之前学过脚本吧···这么强大{/gg}
作者: 3694260ac    时间: 2008-5-17 03:01
学过C++的
作者: 3694260ac    时间: 2008-5-17 03:53
我发现了一些现象:
如果用代码:
class Map
  def initialize
    @devil = Sprite.new
    @devil.bitmap = Bitmap.new("Graphics/Battlers/075-Devil01")
    @devil.ox = -100
    @devil.oy = -100
    @num = 10
      @i = 0

  end
  def input
    if Input.press?(Input::DOWN)
      @devil.oy -= 1
      @i = 0
    while @i < @num
      @i += 1
    end
    end
    if Input.press?(Input::UP)
      @devil.oy += 1
      @i = 0
    while @i < @num
      @i+= 1
    end
    end
    if Input.press?(Input::LEFT)
      @devil.ox -= 1
      @i = 0
    while @i < @num
     @i+= 1
    end
    end
    if Input.press?(Input::RIGHT)
      @devil.ox += 1
      @i = 0
    while @i < @num
      @i+= 1
    end
    end
  end
  def refresh
  end
end



@map = Map.new




loop do
  Graphics.update
  @map.input
  Input.update
end


其中变化的是for变成while,结果按键不会使内存增大,这和i是局部变量或者实变量没关系,初步断定for给i(或者i的一个映射)分配了内存,但是多次调用时并没有完全释放内存,导致内存增大,感觉这种现象很奇怪,感觉不应该发生在编译器上




附带一个小程序:
  @num = 10
  loop do
    for i in 0...@num
    end
    p 1
  end

不断点空格会发现内存也在增大,这说明和Input没什么关系,很可能是内部处理时没处理好,把for改成while并不会出现这个问题



PS :我不知道是不是就我有这种现象!!!!!!!!!!!!!
作者: 雪流星    时间: 2008-5-17 04:06
也就是說,解決問題了嗎?
作者: 3694260ac    时间: 2008-5-17 04:38
我把for都改成while后内存不增加,不过似乎卡了不少,我再改改看吧
作者: 禾西    时间: 2008-5-17 04:39
.........
   @num = 1000
.........
def refresh
   for i in 0...@num
   end
end

驚|||
作者: link006007    时间: 2008-5-17 08:01
在你的工程里  看了一下图块的输出
class Walk
p "Map Sprites Size : " + @map.sprite.size.to_s      # 3600
这个就是卡的正真原因
40*30*3 的图 RM默认其实渲染了40*30*1, 就是人眼所看到的'相对最外层'(可能还会更少, 比如使用视椎切割等)...
Graphics.update 函数每次都会更新到所有的精灵. 而你的代码中
class Map 有一句
update(1), update(2), update(3),
@sprite[(num - 1) * @sprite_num + n].bitmap.blt, 一下3600
FPS 自然降低  如果只update一层, lz的代码效率和RM差不多

测试:

NUM = 1200; # 3600;
  @sprite = Array.new(NUM)
  for i in 0...NUM
    @sprite = Sprite.new
    @sprite.bitmap = Bitmap.new(32, 32)
  end  
  loop do
    Graphics.update
    Input.update
    if Input.trigger?(Input::A)
      break
    end
  end
  for i in 0...NUM
    @sprite.dispose
  end

# NUM ==  1200 ;FPS == 40;   NUM == 3600 ;FPS == 30以下(我电脑上这样) [LINE]1,#dddddd[/LINE]系统信息:本贴获得楼主认可,66RPG感谢您的热情解答~
作者: wy29    时间: 2008-5-17 08:37
提示: 作者被禁止或删除 内容自动屏蔽
作者: link006007    时间: 2008-5-17 08:46
其实  我觉得  lz很厉害...
说新手只是谦虚而已
自己写map渲染不是新手可以做的, 至少我现在没那个信心!
作者: 3694260ac    时间: 2008-5-17 20:09
恩,谢谢!!!我自己再改进改进
作者: 3694260ac    时间: 2008-5-17 20:11
我想如果把所有在一个Z坐标上的sprite整合成一个,应该会好不少
作者: link006007    时间: 2008-5-17 20:24
以下引用3694260ac于2008-5-17 12:11:41的发言:

我想如果把所有在一个Z坐标上的sprite整合成一个,应该会好不少


嗯,3层的sprite都blt到一个单元上,真正需要渲染的地图数组只要一个2D就够了
update(1)  时, x,y上有物体, 就直接bt到2D数组里
update(2)  时, x,y上有物体, 直接在一次blt到update(1)上, 没有就略过
update(3)  如上

不过真的是不是这样,真是不知道了{/gg}
因为RM默认地图渲染的速度确实是和渲染一层一样快, 当然不排除Tilemap用C写
作者: 3694260ac    时间: 2008-5-17 20:25
恩,谢谢楼上的
作者: 3694260ac    时间: 2008-5-17 20:26
不知道楼上的while和for是不是有如上所说的问题
作者: link006007    时间: 2008-5-17 20:40
我一直没看出来你说的while和for的问题究竟是什么{/gg}

我一直都是让你的工程渲染一层来跑的... 一直很顺畅.. 40FPS!!

作者: 靈魂の淚水    时间: 2008-5-17 20:45
提示: 作者被禁止或删除 内容自动屏蔽
作者: 3694260ac    时间: 2008-5-17 20:58
我的for i in 0...@num在不断调用时,会不断增加内存,这个内存的增长量还是满大的,最终导致程序崩溃,正常来说应该申请多少内存给i这个局部变量后应该释放,然而while却没这个问题,令我很奇怪

可以看:
class Map
def initialize
   @devil = Sprite.new
   @devil.bitmap = Bitmap.new("Graphics/Battlers/075-Devil01")
   @devil.ox = -100
   @devil.oy = -100
   @num = 1000
end
def input
   if Input.press?(Input::DOWN)
     @devil.oy -= 1
     refresh
   end
   if Input.press?(Input::UP)
     @devil.oy += 1
     refresh
   end
   if Input.press?(Input::LEFT)
     @devil.ox -= 1
     refresh
   end
   if Input.press?(Input::RIGHT)
     @devil.ox += 1
     refresh
   end
end
def refresh
   for i in 0...@num
   end
end
end
@map = Map.new
loop do
Graphics.update
@map.input
Input.update
end

@num小一些没问题,但是按键移动后看任务管理器Game.exe的内存占用量在增加,改while后不会有问题

作者: 3694260ac    时间: 2008-5-17 21:05
以下引用靈魂の淚水于2008-5-17 12:45:22的发言:

LZ是新手我就去撞墙~~!你一个中午就看会了XP的脚本 - -,果然强人太多了……

我之前用win32下的尝试做,做得有点崩溃,刚好看到这个代码风格比较好,于是就看了看,其实就看了帮助信息以及人物位图,地图这些,没有涉及战斗,数据之内的
作者: 禾西    时间: 2008-5-17 21:07
我看到你用
loop do
  for i in @num
  end
  p i
end
|||
這樣就等於10倍的loop do...不爆炸才怪啦|||
loop do 是無限循環啊...
作者: 3694260ac    时间: 2008-5-17 21:09
所以给他来一个p i中断一些循环啊
作者: 3694260ac    时间: 2008-5-17 21:10
这样就可以动态的看内存的增长/........
作者: IamI    时间: 2008-5-17 21:11
空循环比有代码的循环更加占用内存和CPU。关于程序崩溃,个人认为,应该是i的生命周期应该一直到def的end为止,这样又因为外面套着loop,因而有N个i在内存内被申请,最终导致程序崩溃。 [LINE]1,#dddddd[/LINE]系统信息:本贴获得楼主认可,66RPG感谢您的热情解答~
作者: 禾西    时间: 2008-5-17 21:12
p 是不會中斷循環的...
p 只是輸出數據,循環所産生的數據還在內存當中沒有釋放啊...而且你不覺得 for i in 0..10就很浪費內存了嘛?
作者: 3694260ac    时间: 2008-5-17 21:14
以下引用IamI于2008-5-17 13:11:51的发言:

空循环比有代码的循环更加占用内存和CPU。关于程序崩溃,个人认为,应该是i的生命周期应该一直到def的end为止,这样又因为外面套着loop,因而有N个i在内存内被申请,最终导致程序崩溃。

很有道理!!!!!!!!!!!!!!!

作者: 3694260ac    时间: 2008-5-17 21:16
问题就这样把,总的来说,谢谢各位了
作者: IamI    时间: 2008-5-17 21:16
还有一个很SB的问题。把press改成trigger。一次按键可能触发N次press。试一下是不是按住方向键不放就会引起CPU和内存爆升。
作者: link006007    时间: 2008-5-17 21:16
以下引用3694260ac于2008-5-17 12:58:46的发言:

@num小一些没问题,但是按键移动后看任务管理器Game.exe的内存占用量在增加,改while后不会有问题

真的嘿!
refresh 的for 居然真的会时内存缓慢上升...
while就没事

有意思   不过不知为什么....
作者: 3694260ac    时间: 2008-5-17 21:20
是很奇怪,正常来说,一个局部变量不应该影响到外面的
作者: 禾西    时间: 2008-5-17 21:27
據說:
for i in 0..10
end
本質是:
i = nil
[0,1,2,3,4,5,6,7,8,9,10].each do |x|
i = x
end
[LINE]1,#dddddd[/LINE]
while
end
的本質是
begin
end until ...


以上是否爲眞請大家去看源碼... [LINE]1,#dddddd[/LINE]系统信息:本贴获得楼主认可,66RPG感谢您的热情解答~
作者: IamI    时间: 2008-5-17 21:29
以下引用禾西于2008-5-17 13:27:58的发言:

據說:
for i in 0..10
end
本質是:
i = nil
[0,1,2,3,4,5,6,7,8,9,10].each do |x|
i = x
end



while
end
的本質是
begin
end until ...


以上是否爲眞請大家去看源碼...

链表的each?!爆寒……还有请禾西扣我350分重新加到这个帖子的悬赏上,LZ的认可太早了 [LINE]1,#dddddd[/LINE]版主对此帖的评论:『OK』,积分『-350』。这些被扣积分的一半会用于对本帖正确答案的悬赏。 [LINE]1,#dddddd[/LINE]系统信息:本贴获得楼主认可,66RPG感谢您的热情解答~
作者: 3694260ac    时间: 2008-5-17 21:32
LS太认真了...呵呵
其实我也想知道原因....不过这方面的资料似乎比较难搞 [LINE]1,#dddddd[/LINE]版主对此帖的认可:『加回追加分』,积分『+175』。
作者: link006007    时间: 2008-5-17 21:54
以下引用禾西于2008-5-17 13:27:58的发言:
    ... ...

是的


  1. For ... In

  2. Earlier we said that the only built-in Ruby looping primitives were while and until. What's this ``for'' thing, then? Well, for is almost a lump of syntactic sugar. When you write

  3. for aSong in songList
  4.   aSong.play
  5. end

  6. Ruby translates it into something like:

  7. songList.each do |aSong|
  8.   aSong.play
  9. end

  10. The only difference between the for loop and the each form is the scope of local variables that are defined in the body
复制代码
[LINE]1,#dddddd[/LINE]系统信息:本贴获得楼主认可,66RPG感谢您的热情解答~
作者: 沉影不器    时间: 2008-5-17 22:18
提示: 作者被禁止或删除 内容自动屏蔽
作者: 3694260ac    时间: 2008-5-17 23:24
通过楼上几位的观点,我做了一些小试验,我觉得是不是这样的:
先看一个程序:
@num = 10
def aa
  k = 0
  loop do
    array = [0,1,2,3,4,5,6,7,8,9]
    k += 1
    if k%100 == 0
      k = 0
      p 1
    end
  end
end
aa

这个里面有个数组array,运行后表明array应该是不断申请的,并没有完全释放再看一个程序:
@num = 10
def aa
  k = 0
  loop do
    k += 1
    if k%1000 == 0
      k = 0
      p 1
    end
  end
end
aa

用了%1000,但是运行后内存并没有增加

如上几楼所说的:
for i in 0..10
end
本質是:
i = nil
[0,1,2,3,4,5,6,7,8,9,10].each do |x|
i = x
end

说明for循环导致内存的增大是由于[0,1,2,3,4,5,6,7,8,9,10],不断调用而没有完全的释放掉

之后又出现这个问题:
看程序:
@num = 10
def aa
  k = 0
  loop do
    array = [0,1,2,3,4,5,6,7,8,9]
    k += 1
    if k == 5000000
      break
    end
  end
  loop do
    p 1
  end
end
aa

在出现 1 之前,内存在增加,不过随后也在释放,说明RUBY里面数组还是有释放处理的.......

不知道是不是随着时间的推移或者数组量的过大,RUBY还是会进行一些内部处理来释放内存的




作者: 3694260ac    时间: 2008-5-17 23:27
这些感觉已经涉及RUBY编译器内部处理的事了.....
作者: 禾西    时间: 2008-5-17 23:34
都 break 了,當然會被釋放啦 Orz
另外不要問我 GC 甚麽時候跑,前幾天才討論過這個問題,結果無疾而終|||
據說(又是據說),在 do...end 之間的語句爲一個作用域...出了這個作用域以後,不再有用途的內存會被釋放...

另,以上都是禾西YY。不代表就是Ruby的內部機制......................................
作者: IamI    时间: 2008-5-17 23:37
如果object有定义dispose方法最简单的办法就是把所有东西一概统统dispose
作者: 3694260ac    时间: 2008-5-17 23:46
在break之前也能看出内存的上下变动的

原来是GC,非常感谢
做了一个试验,果然如此:

@num = 10
def aa
  k = 0
  loop do
    array = [0,1,2,3,4,5,6,7,8,9]
    k += 1
    if k%1000 == 0
      GC.start
    end
  end
end
aa



每100次GC一次,内存不再增加了!!!!!!!!!!!!!!!!!!!!
差不多就是这些原因了
作者: 禾西    时间: 2008-5-18 00:02
你是每一千次啓動一次 GC 吧?==|||
[LINE]1,#dddddd[/LINE]
睡覺前最後一回帖:
根據測試,GC.start 是啓動GC,至於是否釋放內存還要看寫法與rp...
Ruby 內部有一套自行判斷是否需要回收內存的機制...
(但是腳本寫法問題一樣會導致系統崩潰)
所以 GC 不是萬能,很多時候要自己注意............

[LINE]1,#dddddd[/LINE]
近來6R多了很多强人,禾西這樣的廢柴版主被問到怕|||
好在有link , 沉影, IamI ,wy29 等等高高手在.....
我看來還是專心放假好了(茶)
作者: 3694260ac    时间: 2008-5-18 00:08
恩,谢谢各位,这个问题就这样吧
学了不少东西,^_^
作者: 3694260ac    时间: 2008-5-18 00:20
不会结了,怎么结啊....BZ帮个忙吧,谢谢




欢迎光临 Project1 (https://rpg.blue/) Powered by Discuz! X3.1