Произошло необработанное исключение типа System.StackOverflowException в my.dll?

Я разрабатываю процесс, который работает под С++ и должен вызываться из веб-сервиса на С#.

В первой версии программы программа на c# успешно работает с dll на c++, состоящей из нескольких классов и одного класса ref со статической функцией.

После этого я создал веб-сервис WCF и перенес свой код:

Функция вызова веб-службы С#:

try
{
    StringBuilder d = new StringBuilder(1000);
    fixed (byte* pt = shelfImage)
    {
        vf.Operations.IdentifyBrands(pt, (int)shelfImage.Length, rowCount, columnCount, d);
    }
    Logger.log("Result is: " + d.ToString());
    return d.ToString();
}

DLL-часть С++:

//Importing GMM and elm data
std::string dataDir = "C:\\VisionFetchData\\";
FeatureExtractor fx;
fx.loadGMM(dataDir+"gmmCigarette.yml");
ELMClassifier* elm = new ELMClassifier(dataDir + "elmv3.bin");

//extracting features and identifying brands
std::vector<float> shelfFeatures = fx.processShelf(mImg, detected);
std::vector<int> ids = elm->classify(shelfFeatures);

Программа успешно работает до последней строки и вылетает на функции классификации еще до входа в тело функции. Ожидается, что ShelfFeatures будет иметь размер 50K-1M. Функция классификатора использует вызов по ссылке для экономии памяти.

Я использую собственную библиотеку в классе ELMClassifier, поэтому мне приходится использовать ELMClassifier* и новое ключевое слово. Я также использовал параметр EIGEN_MAKE_ALIGNED_OPERATOR_NEW в общедоступной части определения класса.

Я пытался:

  • удаление вызова по ссылке на функцию классификатора
  • удаление EIGEN_MAKE_ALIGNED_OPERATOR_NEW и определение указателя класса
  • вызов классификатора с вектором размера 0 (должен возвращать пустой вектор)

Что могло вызвать эту проблему и как я могу ее исправить?


person AutomaticHourglass    schedule 29.06.2015    source источник
comment
Боюсь, вам придется отлаживать дальше. Перехватите исключение и изучите его, посмотрите на трассировку стека и изучите его дальше. Вы говорите, что исключение выдается до того, как будет введена классификация... Это создает впечатление, что это вызвано обычной процедурой вызова функции (например, помещением аргументов в стек, увеличением указателей,...). Но вы сказали, что shelfFeatures передается как ссылка, так что это маловероятно. Вы уверены, что это передано как ссылка? И да, вы должны изучить трассировку стека.   -  person Mercious    schedule 29.06.2015


Ответы (2)


Здесь есть двоякая проблема. Во-первых, размер стека .exe по умолчанию составляет 1 МБ. Итак, ваша переменная shelfFeatures уже хранит большую часть этого, поверх стека, обслуживающего ваш управляемый код C#. Вы играете в опасную игру с выделением памяти, тем более что elm->classify возвращает копию, которая затем снова копируется в ids. Вы фактически удваиваете объем памяти в один момент времени — неудивительно, что ваш стек переполняется! Кроме того, вы делаете то же самое, когда создаете shelfFeatures -- оно копируется из вызова функции.

У вас есть пара вариантов. Сначала разместите в куче и не забудьте потом уничтожить. Кроме того, вы можете установить размер стека исполняемого файла здесь.

person Tasos Stamadianos    schedule 29.06.2015
comment
Я не думаю, что это правильный ответ, потому что, во-первых, elmv3.bin - это огромный файл (300 МБ), который хранится в памяти, должно быть, куча. Во-вторых, 'shelfFeatures' имеет размер 327680, что, по вашему определению, само по себе превышает размер стека, но программа продолжается. В-третьих, насколько я знаю, векторы не копируются, если вы используете их с вызовом по ссылке. Если вы говорите, что параметры функции размещаются в стеке и поэтому должны быть меньше 1М, я понимаю. Однако, как я уже сказал, все векторы передаются по ссылке в функции, чтобы избежать накладных расходов на копирование. - person AutomaticHourglass; 29.06.2015
comment
Вектор, переданный в функцию, передается по ссылке да, но возвращаемые вами векторы передаются в стек как копия, а затем копируются. И куча намного больше, 2 ГБ на exe, если вы не укажете, что он занимает больше. - person Tasos Stamadianos; 29.06.2015
comment
Я попытался передать пустой вектор, который дал такое же исключение. После того, как вы посоветовали не передавать параметры, я преобразовал процедуры вызова по ссылке в указатели, что не решило проблему. Возможно, проблема с Эйгеном? - person AutomaticHourglass; 30.06.2015

Наконец-то решил проблему, ни Эйгена, ни звонка по ссылке делать нечего. Просто стек пространства.

Судя по всему, статически размещенные переменные занимают место в стеке, и массив из 100000 элементов доказывает ему проблему. Изменил мой внутренний массив (должен быть статическим) на управляемый (500) размер, и проблема решена.

Спасибо за вашу помощь.

person AutomaticHourglass    schedule 30.06.2015