На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела Visual Basic: Общие вопросы
Здесь обсуждаются вопросы по языку Visual Basic 1-6 (а так же по схожим языкам, как, например, PowerBASIC).
Вопросы по Visual Basic .NET (это который входит в состав Visual Studio 2002/2003/2005/2008+, для тех, кто не в курсе) обсуждаются в разделе .NET.

Обратите внимание:
1. Прежде чем начать новую тему или отправить сообщение, убедитесь, что Вы не нарушаете правил форума!
2. Обязательно воспользуйтесь поиском. Возможно, Ваш вопрос уже обсуждали. Полезные ссылки приведены ниже.
3. Темы с просьбой выполнить какую-либо работу за автора в этом разделе не обсуждаются. Студенты, вам сюда: ПОМОЩЬ СТУДЕНТАМ!
4. Используйте теги [ code=vba ] ...текст программы... [ /code ] для выделения текста программы подсветкой.
5. Помните, здесь телепатов нет. Формулируйте свой вопрос максимально грамотно и чётко: Как правильно задавать вопросы
6. Запрещено отвечать в темы месячной (и более) давности, без веских на то причин.

Полезные ссылки:
user posted image FAQ Сайта user posted image FAQ Раздела user posted image Кладовка user posted image Наши Исходники user posted image API-Guide user posted image Поиск по Разделу user posted image MSDN Library Online user posted image Google

Ваше мнение о модераторах: user posted image SCINER, user posted image B.V.
Модераторы: SCINER, B.V.
  
> Out of memory для одномерного массива Double - каждый раз разное? , Visual Basic v.6.0.
    Эмпирическим путем 2 дня назад вывел максимальное число элементов в массиве до переполнения: 50102267. Сегодня - этот массив оказался неспособен к расширению даже до 33554432.

    Что происходит?
      :lool:
      Вчера на машине ехал 150 - нормально. А сегодня на 20 уже трясёт так, что того и гляди развалится... а то, что вчера автобан, а сегодня просёлок, с машиной ну никак не связано.
        Цитата Сергей85 @
        Что происходит?

        Фрагментация
          Цитата B.V. @
          Цитата Сергей85 @
          Что происходит?

          Фрагментация

          А почему происходит это? У меня 32 гига оперативки; ну не может ему не хватать разместить этот массив целым где-нибудь на 30-м гигабайте.

          Добавлено
          Цитата Akina @

          Я не менял рабочую машину и кол-во запускаемых программ. Ребут тоже не помогает.
            Почитайте здесь:
              Цитата __Sergey__ @

              Мне для массива память надо заранее зарезервировать - и смогу запихнуть хоть 60миллионов значений?
                Цитата Сергей85 @
                Мне для массива память надо заранее зарезервировать - и смогу запихнуть хоть 60миллионов значений?

                чем отличается виртуальная память от физической?
                  Цитата __Sergey__ @

                  В моем случае это не важно: файл подкачки отсутствует.
                    Цитата __Sergey__ @
                    чем отличается виртуальная память от физической?

                    Цитата Сергей85 @
                    В моем случае это не важно: файл подкачки отсутствует.

                    :no:
                    У каждого процесса\приложения свое собственное виртуальное адресное пространство (АП), в котором выделенные блоки памяти (регионы адресов) проецируются ОС на физ.память (ОЗУ или файл подкачки). Обычному 32-битному процессу доступно всего лишь 2 Гб виртуальных адресов независимо от разрядности ОС и размера ОЗУ. Причем в этих же 2 Гб размещаются не только пользовательские данные, но и код самого приложения и всех используемых им (явно или не явно) системных dll. Примеры распределения памяти процесса можно посмотреть в таблицах 13-2 и 13-3 по приведенной выше ссылке на Рихтера. Посмотреть распределение памяти в собственной программе можно с помощью утилиты VMMap от М.Руссиновича. Основным параметром, определяющим возможность выделения большого массива данных, является Free\Largest - размер свободного региона виртуальной памяти максимального размера. Если он меньше требуемого размера массива, то получишь Out of memory. Посмотри, чему у тебя равно это значение и изменяется ли оно от запуска к запуску
                      Цитата Сергей85 @
                      В моем случае это не важно: файл подкачки отсутствует.

                      :facepalm:
                        Цитата leo @

                        Ну, пусть есть некая флуктуация некоей памяти при каждой перезагрузке. Но как проблему-то решить? Нужно массив будет 2^25 создать - как это сделать? Уж очень близко я к этому пределу подобрался. П.с.: 2^24 работают на всех машинах; проверил даже на старье 2ГБ RAM.
                          Цитата Сергей85 @
                          Но как проблему-то решить? Нужно массив будет 2^25 создать - как это сделать?

                          Чтобы решить проблему, нужно понять из-за чего она возникает.
                          Одномерный массив double из 225 элементов имеет размер всего лишь 268 Мб - это слишком мало, чтобы облом мог происходить из-за начальной фрагментации АП из-за загрузки всевозможных dll. Скорее всего ты что-то не договариваешь - возможно у тебя не один массив, а несколько, или память под массив ты выделяешь не однократно, а несколько раз увеличиваешь его размер через Redim Preserve, или еще что ...

                          Цитата Сергей85 @
                          проверил даже на старье 2ГБ RAM

                          Размер RAM тут роли не играет - при отсутствии клинической фрагментации АП можно и при 2Гб RAM выделить непрерывный кусок памяти до 1.5-1.7 Гб
                            Цитата leo @



                            6 Dim dNumbers_Array() As Double, dFormula_Array() As Double,
                            ...
                            ReDim dFormula_Array(2 ^ (UBound(dNumbers_Array) + 1) - 2) 'Максимальная размерность массива (сумма по всем направлениям) - 50102267. 33554432 соответствует 2^25 как максимальному количеству анализируемых чисел. Значение "все нули" не используется.


                            Всё.
                              Цитата leo @

                              Сделал несколько массивов 2^23 + Copymemory для них. Не вылетает ничего.

                              Я не понимаю, что мне мешает. Свободной RAM - десятки гигабайт.
                                Цитата Сергей85 @
                                Я не понимаю, что мне мешает. Свободной RAM - десятки гигабайт.

                                Сколько можно повторять, что размер RAM тут никакой роли не играет. Приложение работает не с RAM, а со своими виртуальными адресами, коих у 32-битного процесса всего лишь 2Гб, и часть из них занята различными служебными данными. Скачай VMMap по вышеприведенной ссылке и посмотри, что там у тебя творится с занятыми и свободными адресами.
                                  В общем, решил проблему структурой с кучей массивов по 2^23.

                                  Задав похожие вопросы в других местах - люди ни на одном ПК не могли получить больше 2^27. Питон преуспел в этом больше всех.
                                    Цитата Сергей85 @
                                    люди ни на одном ПК не могли получить больше 2^27.

                                    227*8 = 1 Гб - для 32-битного приложения это нормально.
                                    А вот 223*8 - явно мало. Либо у тебя какие-то левые dll рубят все свободное АП на несколько малых кусков (что мало вероятно), либо ты сам со своими массивами где-то косячишь (что более вероятно). Все это можно легко проверить с помощью VMMap (запустить, сохранить отчет в txt и выложить сюда).
                                      Цитата leo @

                                      Косячит хренова тонна программистов, попробовавших ПРОСТО СОЗДАТЬ массив 2^25? Я уже пишу не от лица 1 человека, а от 10-ти.
                                        Private Sub Command1_Click()
                                        Dim s() As Double

                                        ReDim s(2 ^ 28)
                                        End Sub
                                        Прикреплённая картинка
                                        Прикреплённая картинка

                                        Прикреплённая картинка
                                        Прикреплённая картинка
                                        Сообщение отредактировано: Сергей85 -
                                          Картинки VMMap ты привел совершенно не информативные. На них даже параметр Free\Largest block не виден, не говоря уже о занятых адресах (нужно хотя бы прокрутить нижний список до перехода адресов с 0ххх.. на Хххх..., чтобы увидеть причину фрагментации АП). Но лучше не картинки приводить, а сохранить данные VMMap через File\Save as в формате mmp и выложить их сюда, чтобы можно было увидеть всю картину\карту распределения памяти

                                          Пример: в Excel 2002 пишу аналогичный макрос: массив 2^26 выделяет нормально, 2^27 - облом. Смотрю в VMMap и вижу причину - максимальный свободный блок составляет всего 688 Мб, прокручиваю адреса до перехода с 0ххх.. на Хххх.. и вижу, что причина в самом Excel.exe и прочих приблудах Office, которые грузятся по адресам ~300.. и рубят свободный блок АП ~1.4 Гб примерно пополам.

                                          Цитата Сергей85 @
                                          Косячит хренова тонна программистов, попробовавших ПРОСТО СОЗДАТЬ массив 2^25?

                                          Ты уж определись - 2^25 или 2^27, т.к. разница очень существенная

                                          Добавлено
                                          PS: Единственная полезная инфа от выложенных картинок - это то, что свободный размер памяти у тебя превышает 2 Гб. Это говорит о том, что в твоей проге включен доступ к 3-му гигабайту (LARGE_ADDRESS_AWARE). Тем более не понятно, чем этот 3-й Гб занят, т.к. никакие dll обычно в него не грузятся ...
                                          Сообщение отредактировано: leo -
                                            2^26.
                                            Прикреплённый файлПрикреплённый файлDesktop.zip (37,91 Кбайт, скачиваний: 104)
                                              Цитата Сергей85 @
                                              2^26

                                              Ну и ?
                                              В Project1 максимальный свободный блок памяти составляет 970 Мб, поэтому и "почему-то нет ошибки" при выделении 8*2^26 = 536 Мб.
                                              В vb6 максимальный блок равен 435 Мб (< 536 Мб), поэтому и происходит облом-с. Причина, как обычно, в дурных dll MS Office (в данном случае mso97rt.dll), которые норовят влезть по адресам вблизи 30000000H. Однако, хоть это и неприятно, но терпимо. Ты же уверяешь, что у тебя 2^24-2^25 не всегда выделяются, а это всего лишь 134-268 Мб - сколько еще нужно загрузить дурных dll, чтобы они так раздробили всё адресное пространство?! Можешь выложить пример, где с выделением 2^24-2^25 происходит облом?

                                              Насчет 3-го Гб я ошибся - макс.объем свободной памяти в Project1 не превышает 2Гб. Поэтому кардинальным решением проблемы в 64-битных ОС может быть разрешение для твоей программы использовать 3-й Гб (опция LARGE_ADRESS_AWARE). Это можно сделать с помощью утилиты editbin.exe, которая должна входить в состав VC6 (см. первый попавшийся пример).
                                                ExpandedWrap disabled
                                                  Option Explicit
                                                  Option Compare Text
                                                   
                                                  Dim oExcelApp As New Excel.Application  'Приложение.
                                                  Dim oDocExcel As New Excel.Workbook 'Документ Excel.
                                                  Dim oExWs As New Excel.Worksheet 'Таблица документа Excel.
                                                   
                                                  Dim g_bCancel As Boolean 'Отмена ресурсоемкого процесса.
                                                  Dim g_bCommand_Check_Click_Loaded As Boolean 'Самая ресурсоемкая функция завершила работу и успешно закрыла все приложения.
                                                   
                                                  Private Declare Function InitCommonControls Lib "Comctl32.dll" () As Long 'Для корректной загрузки COMCTL32.OCX в Windows XP.
                                                  Private Declare Function GetDesktopWindow Lib "user32" () As Long
                                                  Private Declare Function ShellExecute& Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long)
                                                  Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long) 'Мгновенное копирование массивов.
                                                   
                                                   
                                                   
                                                   
                                                  Private Sub Command_Check_Click()
                                                  1 On Error GoTo ErrorHandler
                                                   
                                                  'Составление и заполнение массива данных.
                                                  3 Dim dNumbers_Array() As Double, dFormula_Array() As Double
                                                   
                                                   
                                                     'Открытие файла со списком номиналов.
                                                  20 g_oCommonDialog.FileName = ""
                                                  21 g_oCommonDialog.DialogTitle = "Открыть файл .XLS*"
                                                  22 g_oCommonDialog.Filter = "Файлы Microsoft Excel|*.xls*; *.csv"
                                                  23 If g_oCommonDialog.ShowOpen(Me) <> 0 Then Exit Sub
                                                  24 g_oCommonDialog.InitDir = g_oFSO.GetParentFolderName(g_oCommonDialog.FileName)
                                                   
                                                     'Создать приложение Excel и скрытно работать с документом.
                                                  42 Set oExcelApp = New Excel.Application
                                                  43 oExcelApp.Visible = False
                                                  44 oExcelApp.IgnoreRemoteRequests = True
                                                  45 Set oDocExcel = oExcelApp.Workbooks.Open(g_oCommonDialog.FileName, , True)
                                                  46 Set oExWs = oDocExcel.ActiveSheet
                                                   
                                                     'Работа построчно с передачей значений в функцию с формулами расчета. Количество комбинаций чисел - 2^n, что позволяет отказаться от факториалов и биномиального коэффициента.
                                                  47 While oExWs.Cells(lRow + 1, 1) <> ""
                                                  48     ReDim dNumbers_Array(0) 'Максимум чисел - 25.
                                                   
                                                  49     dMaximum_Number = 0
                                                  50     iCol = 0
                                                  51     g_sTemp = ""
                                                      
                                                  52     While oExWs.Cells(lRow + 1, iCol + 1) <> ""
                                                  53         If IsNumeric(oExWs.Cells(lRow + 1, iCol + 1)) Then
                                                  54             If iCol > 0 Then ReDim Preserve dNumbers_Array(iCol)
                                                  55             dNumbers_Array(iCol) = oExWs.Cells(lRow + 1, iCol + 1)
                                                  56             g_sTemp = g_sTemp & dNumbers_Array(iCol) & " "
                                                  57             If dMaximum_Number < dNumbers_Array(iCol) Then dMaximum_Number = dNumbers_Array(iCol)
                                                  58         Else
                                                  59             MsgBox "Ошибка: в строке " & lRow + 1 & " стоблце " & iCol & " указано не положительное число. Операция прервана, результаты на экране."
                                                  60             GoTo endd
                                                  61         End If
                                                   
                                                  62         iCol = iCol + 1
                                                  63     Wend
                                                      
                                                  64     [B]ReDim dFormula_Array(2 ^ (UBound(dNumbers_Array) + 1) - 2) 'Значение "все нули" не используется.[/B]


                                                Добавлено
                                                Не понимаю, как LARGE_ADRESS_AWARE подключается? По примеру фигня какая-то. Ведь получается, что проект должен вызвать editbin сам на себя.
                                                  Используя небольшую хитрость на 64 битных системах можно выделить больше 4ГБ памяти.
                                                    Цитата TheTrik @


                                                    Иииии?..
                                                      Цитата Сергей85 @
                                                      Иииии?..

                                                      Учитывая что любой процесс в 64 битной среде является 64 битным, включая 32 битные то мы можем использовать все преимущества 64 битного режима из 32 битного процесса. Именно для выделения памяти нужно переключится в 64 битный режим, найти ntdll, найти функцию NtAllocateVirtualMemory, вызвать ее, получить указатель в 64 битном пространстве, переключится обратно. Писать/читать либо переключаясь в 64 битный режим либо с помощью функций NtWow64WriteVirtualMemory64/NtWow64ReadVirtualMemory64.
                                                        Цитата Сергей85 @
                                                        Не понимаю, как LARGE_ADRESS_AWARE подключается?

                                                        LARGE_ADRESS_AWARE подключается путем простой установки флага в заголовке exe-файла. В продвинутых компиляторах это делается путем задания соответствующей опции линкера. В vb6 такой возможности нет. Поэтому нужно использовать утилиту editbin.exe, которая установит нужный флаг в уже готовом\скомпилированном экзешнике. Для этого нужно в винде выполнить команду "путь\editbin.exe /largeaddressaware путь\имя_твоей_проги.exe". Чтобы каждый раз не набирать эту абру-кадабру, можно в папке с твоей программой создать либо bat-файл (простой текстовый файл с расширением bat) с соответствующей строкой, либо ярлык для editbin.exe, в котором через Свойства изменить строку Объект - добавить " /largeaddressaware имя_твоей_проги.exe". А чтобы не забыть про все это дело, можно в проге добавить вызов функции GlobalMemoryStatusEx (как рекомендовано в примере) с выдачей предупреждения в случае ullTotalVirtual <= 2 Гб.
                                                          Замечания по коду #23.
                                                          1) Тебе уже в соседней ветке указали на то, что объявлять переменные oExcelApp, oDocExcel и oExWs через New не нужно, т.к. во-первых, это не имеет смысла, поскольку в Command_Check_Click ты их все равно устанавливаешь заново, во-вторых, создание Excel.Workbook и Worksheet через New может приводить к той самой ошибке 429 - "ActiveX component can't create object".
                                                          2) Я уже говорил, что вызов диалога открытия файла подгружает кучу разных dll (в том числе и совершенно левых, отвечающих за опции контекстного меню файла) и создает несколько потоков - все это может негативно сказываться на фрагментации адресного пространства твоей проги. Работа с объектами Excel также может приводить к подгрузке офисных dll, созданию расшареных регионов памяти и т.п. Поэтому, раз у тебя максимальный размер массива dFormula_Array не может превышать 2^25*8 = 268 Мб (по сути - это "мелочь пузатая"), то лучше выделить память под него сразу при старте проги (до вызова диалога открытия файла и создания объектов Excel - например, в Form_Load). Если в Command_Check_Click окажется, что для массива нужно меньше памяти, то можно сделать ReDim для уменьшения его размера (только без Preserve - иначе м.б. облом!)

                                                          PS: Наращивать длину массива dNumbers_Array по одному элементу, когда их максимальное число не может превышать 25 - это как-то э-э-э, "не профессионально". Проще использовать статический массив (можно с запасом, например на 32 элемента), а реальное кол-во используемых элементов хранить в отдельной переменной типа dNumbers_Count As integer
                                                          Сообщение отредактировано: leo -
                                                            1) Пробовал с разными вариантами перетасовки New - ошибка не меняется.
                                                            2) Ясно.

                                                            PS: что быстрее: Ubound(Array) или int при указании в условиях цикла For? Мне скорость циклов важнее, чем скорость заполнения массива dNumbers.
                                                              Цитата Сергей85 @
                                                              что быстрее: Ubound(Array) или int при указании в условиях цикла For?

                                                              Теоретически int "быстрее", но практически в цикле For ты разницы не заметишь, т.к. при For верхний предел (по идее) должен вычисляться только один раз перед входом в цикл (а не на каждой итерации как в while и do..loop)
                                                                Цитата leo @
                                                                В vb6 такой возможности нет.

                                                                Есть.
                                                                  Извините за оффтоп. Сергей, ты наверно один остался на VB6? Может подумаешь?
                                                                    Цитата AndreyMp @
                                                                    Сергей, ты наверно один остался на VB6?

                                                                    Осталось много, он один, кто активно спрашивает.
                                                                    0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                                                    0 пользователей:


                                                                    Рейтинг@Mail.ru
                                                                    [ Script execution time: 0,0906 ]   [ 20 queries used ]   [ Generated: 28.04.24, 16:59 GMT ]